c# 根据输入指定方法调用?

发布于 2024-11-27 09:48:27 字数 900 浏览 1 评论 0原文

如何最好地允许 ac# 程序的输入来控制方法调用?例如:

假设我们有一个委托类型:

delegate void WriteMe(); 

和几个方法:

void PrintInt() { Console.WriteLine(10); }
void PrintString() { Console.WriteLine("Hello world."); }

并允许输入选择调用顺序:

public static WriteMe ProcessInvocationInput(int[] val) {
    WriteMe d = null; 
    foreach (int i in val) {
        switch (i) {
            case 1: d += PrintInt; break; 
            case 2: d += PrintString; break; 
        } 
    }
}

以及调用这一切的代码:

static void Main(string args[]) {
    int[] values = {1, 2, 3}; // Obviously this array could be filled 
                              // from actual input (args, file, wherever)
    WriteMe d = ProcessInvocationInput(values); 

    d(); 
}

我发布这个问题的原因是因为它实现起来似乎相当复杂这似乎是一个简单的想法。我知道实现此行为的另一种方法是使用反射 API,但这会更加复杂。

How would one best go about allowing the input of a c# program to control method invocation? For example:

Assume we have a delegate type:

delegate void WriteMe(); 

And a couple of methods:

void PrintInt() { Console.WriteLine(10); }
void PrintString() { Console.WriteLine("Hello world."); }

And allowing the input to select the invocation order:

public static WriteMe ProcessInvocationInput(int[] val) {
    WriteMe d = null; 
    foreach (int i in val) {
        switch (i) {
            case 1: d += PrintInt; break; 
            case 2: d += PrintString; break; 
        } 
    }
}

And the code that calls it all:

static void Main(string args[]) {
    int[] values = {1, 2, 3}; // Obviously this array could be filled 
                              // from actual input (args, file, wherever)
    WriteMe d = ProcessInvocationInput(values); 

    d(); 
}

The reason I'm posting this question is because it seems rather complex to implement what seems like a simple idea. I know another way to accomplish this behavior is with the reflection API, but that would be even more convoluted.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葵雨 2024-12-04 09:48:28

如果您为您可以执行的操作创建值字典

 private static Dictionary<int,Action> _actions=new Dictionary<int,Actions> {
     {1, PrintInt},
     {2, PrintString},
 };

那么您可以循环和处理

foreach (var item in input) _actions[item]();

If you create a dictionary of values to Actions you can do

 private static Dictionary<int,Action> _actions=new Dictionary<int,Actions> {
     {1, PrintInt},
     {2, PrintString},
 };

Then you can just loop and process

foreach (var item in input) _actions[item]();
时光瘦了 2024-12-04 09:48:27

这实际上取决于您想要涵盖的范围。对于简单的情况,您可以使用开关(我建议使用枚举来明确说明):

enum InputCommands
{
    PrintHelloWorld = 1,
    ExecuteFixedBinary = 2,
    ...
}

switch((InputCommands)inputInt)
{
    case InputCommands.PrintHelloWorld: ...
    case InputCommands.ExecuteFixedBinary: ...
}

但是如果您正在编写 shell,则需要更强大的东西,例如某种 IExecutableCommand 接口由各个类实施。

interface IExecutableCommand
{
    void Execute(string arg);
}

您将必须实现一些解析器来处理多个调用请求和/或处理更复杂的参数。

如果您想使用反射,请务必验证您的输入!这可以通过仅执行具有自定义属性的方法来完成。

class ExecutableMethodAttribute : Attribute { }

[ExecutableMethod]
void Foo() 
{ 
   ...
}

使用此属性过滤掉方法非常简单:

someAssembly.GetTypes()
  .SelectMany(t => t.GetMethods())
  .Where(mi => mi.GetCustomAttributes(typeof(ExecutableMethodAttribute), true).Any())

That really depends on the scope you're trying to cover. For simple cases you could use a switch (I'd suggest and enum to make it clear):

enum InputCommands
{
    PrintHelloWorld = 1,
    ExecuteFixedBinary = 2,
    ...
}

switch((InputCommands)inputInt)
{
    case InputCommands.PrintHelloWorld: ...
    case InputCommands.ExecuteFixedBinary: ...
}

But if you're writing a shell, than you need something more robust, like some sort of IExecutableCommand interface implemented by various classes.

interface IExecutableCommand
{
    void Execute(string arg);
}

You will have to implement some parser to handle multiple invocation requests and/or handle more complex arguments.

If you want to use Reflection, be sure to validate your input! That could be done by only executing methods with a custom attribute on them.

class ExecutableMethodAttribute : Attribute { }

[ExecutableMethod]
void Foo() 
{ 
   ...
}

Filtering out methods with this attribute is easy enough:

someAssembly.GetTypes()
  .SelectMany(t => t.GetMethods())
  .Where(mi => mi.GetCustomAttributes(typeof(ExecutableMethodAttribute), true).Any())
秋意浓 2024-12-04 09:48:27
public static ICollection<Action> ProcessInvocationInput(int[] val)
{
    var actions = new List<Action>();
    foreach (int i in val)
    {
        switch (i)
        {
            case 1: actions.Add(PrintInt);
            case 2: actions.Add(PrintString);
        }
    }

    return actions;
}

...
foreach (var action in ProcessInvocationInput(input))
{
    action();
} 
public static ICollection<Action> ProcessInvocationInput(int[] val)
{
    var actions = new List<Action>();
    foreach (int i in val)
    {
        switch (i)
        {
            case 1: actions.Add(PrintInt);
            case 2: actions.Add(PrintString);
        }
    }

    return actions;
}

...
foreach (var action in ProcessInvocationInput(input))
{
    action();
} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文