将方法存储在数组中并在C#中调用它们

时间:2017-02-10 12:28:49

标签: c# .net function

在javascript中我们可以这样做:

var arr = [];

function fooBar() {
    console.log('Hello World');
}

arr[0] = fooBar;

arr[0]();

基本上每个函数都是一个真实对象,如果我愿意,我可以将它们存储在一个数组中。我的问题是,由于C#没有指针,处理这种情况的最佳方法是什么?我的意思是如何将函数引用存储到数组中?

我知道我们有一些名为委托的东西,但我不确定这是否适合这项任务......

6 个答案:

答案 0 :(得分:9)

代表完全你需要的东西:

var list = new List<Action>();

...

void fooBar() {
    ....
}

...

list.Add(fooBar);

Action实际上只是一个delegate,只是看看它的定义,你会发现它类似于一个期待什么也没有返回的代表。如果要传递参数,请使用任何通用版本,例如Action<T>。如果您还需要添加返回内容的方法,请使用Func - 委托代替。

编辑:每个代表都有自己的类型,所以除了使用Delegate类型的集合之外,你不能将它们混合在一起并将它们全部放在一个集合中:

var list = new List<Delegate>();

在这种情况下,你不能使用urual括号来调用实际的委托,而是你必须使用DynamicInvoke并根据委托签名传递参数。

list[0].DynamicInvoke(args);

答案 1 :(得分:6)

代表是正确的任务 - 它们等同于强类型函数指针。

因为每个委托都是它自己的类型,所以不能将数组类型中的不同委托类型混合并匹配到单个委托类型,您可以使用父System.Delegate来存储不同类型的委托在数组中,虽然你没有能力直接调用它们而没有一些通道给你的程序通知他们的参数。

例如:

public static String Meow(Cat cat) { return "meow"; }
public static String Purr(Cat cat) { return "purr"; }

delegate String CatSound(Cat cat);

CatSound[] catSounds = new CatSound[] {
    Meow,
    Purr
};

然后您可以直接调用它们:

Cat orion = new Cat();
catSounds[0]( orion ); // meow
catSounds[1]( orion ); // purr

如果您想为自己的收藏添加DogSound代表,那么您将面临更艰难的工作:您需要使用Delegate[]代替......

delegate String DogSound(Dog dog);

Delegate[] petSounds = new Delegate[] {
    new CatSound( Meow ),
    new CatSound( Purr ),
    new DogSound( Woof ),
    new DogSound( Bark ),
}; // note that C# compiler allows shorthand syntax where simply `Meow` is behind-the-scenes converted into `new CatSound( Meow )`.

...你必须使用DynamicInvoke方法(https://msdn.microsoft.com/en-us/library/system.delegate.dynamicinvoke(v=vs.110).aspx)调用它,这意味着你将失去正确参数的编译时验证,而不是使用不正确的参数进行的任何调用将在运行时使用MemberAccessException失败。

Dog pupper = new Dog();
Cat orion = new Cat();

petSounds[0].DynamicInvoke( orion );
petSounds[1].DynamicInvoke( orion );
petSounds[2].DynamicInvoke( pupper ); // ok, this is a DogSound
petSounds[3].DynamicInvoke( orion ); // this will fail at runtime because you're passing a Cat into a DogSound delegate

您还可以将delgates视为&#34; interface用于单个方法&#34;。

在.NET Framework 3.5之前,您通常需要使用delegate关键字定义自己的委托类型(请注意,对于C#3.0中的匿名函数,delegate关键字也会重载),但是现在有System.ActionSystem.Func为95%的情况提供服务,您以前需要定义自己的类型。实际上,今天我的delegate CatSound是不必要的,您可以改为使用Func<Cat,String>

答案 2 :(得分:3)

鉴于要调用的函数具有相同的签名,可以使用预定义的generics for delegates完成,如下所示。

Func<int,int> Square = x => x*x;
Func<int,int> Successor = x => x+1;
Func<int,int> Functions[] = new Func<int,int>[]{ Square, Successor };

int A = Functions[0](2); // A gets assigned 4;
int B = Functions[1](1); // B gets assigned 2;

答案 3 :(得分:3)

您可以存储Action或Func对象,例如:

void Main()
{
    var arr = new object[2];
    arr[0] = 1;
    arr[1] = (Action)DoIt;

    foreach (var a in arr)
    {
        if (a is Action)
        {
            ((Action)a)();
        }
        else
        {
            Console.WriteLine(a.ToString());
        }
    }
}


public void DoIt()
{
    Console.WriteLine("did");       
}

答案 4 :(得分:2)

考虑行动(取决于.net版本)

https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx

List<Action<string>> actions = new List<Action<string>>();

    actions.Add(() => {
      //do stuff
    });

或者如果您需要rturn值,请使用Func:https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx

答案 5 :(得分:2)

是的,通过代表你可以:

static void iammain()
{
  List<Action> lst = new List<Action>();
  lst.AddRange(new Action[] { proc1, proc2, proc3 });
  for (int i = 0; i < lst.Count; i++)
  {
    lst[i]();

  }

}
static void proc1()
{
  Console.WriteLine("i am proc1");

}
static void proc2()
{
  Console.WriteLine("i am proc2");

}
static void proc3()
{
  Console.WriteLine("i am proc3");

}