【问题标题】:Can methods be called via an array in C#?可以通过 C# 中的数组调用方法吗?
【发布时间】:2012-07-11 17:06:50
【问题描述】:

我有一个程序需要运行不同的方法,具体取决于我希望它与之交谈的内容,我想知道是否有一种方法可以将某种方法指针或类似的东西存储在数组中。所以我想要一个数组,其中每个元素都是这样的:

[Boolean: Do_this?] [Function_pointer] [要传递给函数的数据]

所以基本上,我可以把它放到一个 for 循环中,而不是单独调用每个函数。另一个代码块将填写是否运行此函数的布尔值,然后如果布尔值为真,我的 for 循环将通过并使用其适当的数据运行该函数。

我知道委托类似于函数指针,但如果这就是这里的答案,我不完全确定如何构造我想要构造的东西。

这在 C# 中可行吗?

【问题讨论】:

    标签: c# arrays methods delegates


    【解决方案1】:

    当然,不过,要这样做,您需要所有方法都具有相同的签名:

    假设您有两种方法:

    public int Moop(string s){ return 1; }
    public int Moop2(string s){ return 2; }
    

    你可以这样做:

    var funcs = new Func<string, int>[]{ Moop, Moop2 };
    

    然后调用:

    var val = funcs[0]("hello");
    

    【讨论】:

      【解决方案2】:

      您可以声明要保存在委托中的特定对象类型、指示是否执行此操作或现在执行此操作的标志以及数据。请注意,您所描述的内容与 events 非常相似,因为它们也是由回调和一些事件数据定义的。

      假设您要调用的所有方法都具有相同的签名,骨架模型看起来像这样(如果您需要大量不同的签名,可以使用反射来解决这个问题):

      // This reflects the signature of the methods you want to call
      delegate void theFunction(ActionData data);
      
      class ActionData
      {
          // put whatever data you would want to pass
          // to the functions in this wrapper
      }
      
      class Action
      {
          public Action(theFunction action, ActionData data, bool doIt)
          {
              this.action = action;
              this.data = data;
              this.doIt = doIt;
          }
      
          public bool doIt
          {
              get;
              set;
          }
      
          public ActionData data
          {
              get;
              set;
          }
      
          public theFunction action
          {
              get;
              set;
          }
      
          public void run()
          {
              if (doIt)
                  action(data);
          }
      }
      

      一个常规的用例看起来像这样:

      class Program
      {
          static void someMethod(ActionData data)
          {
              Console.WriteLine("SUP");
          }
      
          static void Main(string[] args)
          {
              Action[] actions = new Action[] {
                  new Action(Program.someMethod, new ActionData(), true)
              };
      
              foreach(Action a in actions) 
                  a.run();
          }
      }
      

      【讨论】:

      • 虽然这个选项相当长,但我还是决定使用这个选项,因为它的可读性非常好,应该能满足我的需要。感谢您的帮助。其他答案也很好,但我认为从长远来看,这个答案最有帮助。
      • 是的,我同意它的内部有一种 Java 冗长的感觉,但我觉得这种方法比模板化数组方法更清晰一些。另外,您应该查看@Servy 的回复,因为它似乎提供了一个更简洁的替代方案(尽管缺少enabled 标志)。
      • @AndreiBârsan 我确实在 cmets 中有一个“启用”标志。在执行某些代码块之前,如果它不应该存在,则不实际添加该方法,添加无操作操作或让方法本身检查,这很容易。
      • 啊,是的,重新阅读您的问题后,我意识到了这一点!好吧,我很高兴我的这部分答案没有妨碍您。 :)
      【解决方案3】:

      是的,你可以。

      如果您的所有函数共享相同的签名,您可能希望将委托存储在您的集合中,否则我会选择System.Reflection.MethodInfo,您可以稍后通过调用Invoke 方法使用它。参数将存储为对象数组 - 这就是 Invoke 所期望的。

      如果使用反射太慢,可以使用Reflection.Emit在运行时生成动态方法。

      【讨论】:

        【解决方案4】:

        我会创建一个List&lt;Action&gt;。 Action 是一个不带参数且不返回结果的委托。您可以使用 currying 和 lambda,以便实际操作可以调用具有参数的方法。如果您实际上不想运行它,请首先不要将其添加到列表中(或者添加一个我猜什么都不做的操作)。

        要添加一个项目,它可能看起来像:

        list.Add(() => someobject.someMethod(firstArgument, secondArgument));
        list.Add(() => anotherObject.anotherMethod(oneArgument));
        

        然后,您可以在需要时运行所有操作:

        foreach(Action action in list)
        {
          action();
        }
        

        【讨论】:

          【解决方案5】:

          这正是您使用委托的目的。委托或多或少是经过类型检查的函数指针。您可以创建一些委托并将它们放入一个数组中。

          Func<int, int> [] funcs = new Func<int,int>[] { x => 2 * x, x => x * x };
          foreach(var fn in funcs) 
          {
              Console.WriteLine(fn(3));
              Console.WriteLine(fn(8));
          }
          

          【讨论】:

            猜你喜欢
            • 2014-11-14
            • 2016-06-13
            • 1970-01-01
            • 2014-08-03
            • 2015-06-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多