要了解此行为,您需要了解两件事。
- 所有代表都来自
System.Delegate
,但是不同的代表具有不同的类型,因此不能彼此分配。
- C#语言为将方法或lambda分配给委托人提供了特殊的处理方法。
由于不同的委托具有不同的类型,这意味着您不能将一种类型的委托分配给另一种。
例如,给定:
delegate void test1(int i);
delegate void test2(int i);
然后:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
上面的第一行编译OK,因为它使用特殊处理将lambda或方法分配给委托。
实际上,编译器可以有效地重写此行:
test1 a = new test1(Console.WriteLine);
上面的第二行未编译,因为它试图将一种类型的实例分配给另一种不兼容的类型。
就类型而言,在test1
和之间没有兼容的分配,test2
因为它们是不同的类型。
如果可以考虑一下,请考虑以下类层次结构:
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
下面的代码将无法编译,即使Test1
与Test2
来自同一个基类派生:
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
这解释了为什么您不能将一种委托类型分配给另一种。那只是普通的C#语言。
但是,关键是要了解为什么允许您将方法或lambda分配给兼容的委托。如上所述,这是对委托的C#语言支持的一部分。
因此,最后回答您的问题:
使用时,Invoke()
您将使用特殊的C#语言处理将方法调用分配给委托,以便将方法或lambda分配给委托,而不是尝试分配不兼容的类型-因此它可以编译。
完全清楚,在您的OP中编译的代码:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
实际上在概念上转换为:
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
而失败的代码正在尝试在两种不兼容的类型之间进行分配:
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}