我在下面汇总了一个小代码示例(目前在 C# 3.5 中,但也想知道答案在 C# 4.0 中是否有任何不同)
我有三个简单的委托和三个简单的函数......这里没问题,一切都按预期编译,如果我不小心尝试将委托 A 与方法 B 等链接(参数数量错误),将无法编译。
我正在努力理解的是为什么匿名函数似乎很乐意与所有三个命名的代表联系起来
public class Foo
{
public delegate void del_TestWithNoParams();
public delegate void del_TestWithThreeInts(int x, int y, int z);
public delegate void del_TestWithIntPtr(IntPtr ptr);
public void DoStuff()
{
//All OK so Far ... Code will not compile if I mix these up
del_TestWithNoParams d1 =
TestWithNoParams; d1();
del_TestWithThreeInts d2 =
TestWithThreeInts; d2(2, 4, 8);
del_TestWithIntPtr d3 =
TestWithIntPtr; d3(new IntPtr(0x1234567));
//Why do these compile
del_TestWithNoParams d4_nocompile =
delegate { Console.WriteLine("AnonymousDel d4"); };
del_TestWithThreeInts d5_nocompile =
delegate { Console.WriteLine("AnonymousDel d5"); };
del_TestWithIntPtr d6_nocompile =
delegate { Console.WriteLine("AnonymousDel d6"); };
// Edit 1 goes here
}
public void TestWithNoParams()
{ Console.WriteLine("NoParams"); }
public void TestWithThreeInts(int x, int y, int z)
{ Console.WriteLine("Ints: {0},{1},{2}", x, y, z); }
public void TestWithIntPtr(IntPtr ptr)
{ Console.WriteLine("IntPtr: 0x{0:X8}", ptr.ToInt32()); }
}
另外(只是为了给你一个完整的可运行的应用程序......)
static void Main(string[] args)
{
var f = new Foo();
f.DoStuff();
Console.WriteLine("Done"); Console.ReadLine();
}
编辑 1:使用 Lambda 方法
//This work as expected - and fail to build if I get the parameter-count wrong.
del_TestWithNoParams d7 =
(() => Console.WriteLine("Lambda NoParams"));
del_TestWithThreeInts d8 =
((a, b, c) => Console.WriteLine("Lambda Ints: {0},{1},{2}", a, b, c));
del_TestWithIntPtr d9 =
((ptr) => Console.WriteLine("Lambda IntPtr: 0x{0:X8}", ptr.ToInt32()));
Test(d7, d8, d9);
简单的辅助函数:
private void Test(del_TestWithNoParams del_A, del_TestWithThreeInts del_B, del_TestWithIntPtr del_C)
{
del_A();
del_B(2, 4, 8);
del_C(new IntPtr(0x1234567));
}
...您是否同意这是编写相同代码的更好方法?
编辑 #2 - 答案摘要
我意识到(无论我以哪种方式编写代码),生成的 IL 字节码仍然是类型安全的。
与 C# 中的许多东西一样,命名委托、匿名委托和 lambda 方法各有各的位置,在“代码可读性”、“代码编译器扩展”和个人适用性之间存在平衡正在编写的应用程序。
下面的回复帮助回答了这个问题,并表明编译器确实在做类似于以下的事情。
1 - 它不会让我犯这个错误
//del_TestWithIntPtr d_mistake_A =
// delegate(int x,int y,int z) { Console.WriteLine(x + y + z); };
2 - “编译器推断类型”将委托(例如 d5_nocompile)扩展为
del_TestWithThreeInts d_clearer_3P =
delegate(int x, int y, int z) { Console.WriteLine(x + y + z); };
3 - 可能会出错(仍然是有效代码)
del_TestWithThreeInts d_EasyToMakeMistake =
delegate { Console.WriteLine("Oops - forgot to do anything with params"); };
// (this is really :- delegate (int x, int y, int z) {...} )
4 - 但是,当重写为 lambda 表达式时,稍后(或向其他开发人员)查看代码时会稍微明显一些
del_TestWithThreeInts d_LessEasyToMakeMistake =
((x, y, z) => Console.WriteLine("Still POSSIBLE to make mistake, but more obvious"));