在javascript中我们可以这样做:
var arr = [];
function fooBar() {
console.log('Hello World');
}
arr[0] = fooBar;
arr[0]();
基本上每个函数都是一个真实对象,如果我愿意,我可以将它们存储在一个数组中。我的问题是,由于C#没有指针,处理这种情况的最佳方法是什么?我的意思是如何将函数引用存储到数组中?
我知道我们有一些名为委托的东西,但我不确定这是否适合这项任务......
答案 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.Action
和System.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");
}