隐式和显式委托创建之间的区别(有和没有generics)

请参阅下面的Go()方法中的四行:

delegate void Action(T arg); delegate void Action(); void DoSomething(Action action) { //... } void DoSomething(Action action) { //... } void MyAction(T arg) { //... } void MyAction() { //... } void Go() { DoSomething(MyAction); // throws compiler error - why? DoSomething(new Action(MyAction)); // no problems here DoSomething(MyAction); // what's the difference between this... DoSomething(new Action(MyAction)); // ... and this? } 

请注意,第一次调用生成的编译器错误是: 无法从用法推断出方法“Action(T)”的类型参数。 尝试显式指定类型参数。

MyActionnew Action(MyAction)之间没有区别(当它们都有效时),除了前者在C#1中不起作用。这是implicit method group conversion 。 有些时候这是不适用的,最值得注意的是当编译器无法确定你想要什么样的委托时,例如

 Delegate foo = new Action(MyAction); // Fine Delegate bar = MyAction; // Nope, can't tell target type 

这会在您的问题中发挥作用,因为所涉及的两种方法都会过载。 这基本上导致了头痛。

至于generics方面 – 这很有趣。 方法组没有得到C#3类型推断的太多爱 – 我不确定它是否会在C#4中得到改进。 如果您调用generics方法并指定类型参数,则类型推断可以很好地工作 – 但如果您尝试以相反的方式执行此操作,则会失败:

 using System; class Test { static void Main() { // Valid - it infers Foo DoSomething(Foo); // Valid - both are specified DoSomething(Foo); // Invalid - type inference fails DoSomething(Foo); // Invalid - mismatched types, basically DoSomething(Foo); } static void Foo(T input) { } static void DoSomething(Action action) { Console.WriteLine(typeof(T)); } } 

C#3中的类型推断非常复杂,并且在大多数情况下运行良好(特别是它对LINQ很有用)但在其他一些情况下失败。 在理想的世界中,它将变得更容易理解, 并且在未来的版本中更强大……我们会看到!

非generics隐式委托创建只是语法糖,因此编译器生成完全相同的代码

 DoSomething(MyAction); 

 DoSomething(new Action(MyAction)); 

因为它可以直接从方法参数和上下文推断出委托的类型。

使用通用委托,您必须根据协方差和逆变指定委托类型(有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/ms173174(VS.80).aspx ) – T in Action可以是方法中T的超类型,它仍然可以作为委托方法接受。 因此,您需要在委托中明确指定T,因为编译器无法自行解决。

只是一个旁注..出于某种原因,这适用于VB。

当我将Methodgroup / adderessof转换为委托时,似乎C#中的预处理器的实现和VB不同。