我们知道,在 C# 中,同一个签名定义的委托是不同的类型,例如 delegate int MyDelegate(int arg0);
定义的 MyDelegate
和 Func<int, int>
不是同一个委托类型,并且它们之间没有隐式转换。
讨论缘起于这个 知乎回答,大概是答主对 C# 的委托机制不太了解,以为 C# 的委托是值捕获的(是引用捕获,实现上等价于把被捕获的东西放入一个对象中,然后以这个对象的方法产生一个委托)。在评论的讨论中,作者提问如何让一个匿名方法返回自己,以及如何让两个匿名方法互相返回,答案是容易尝试的:
class Program
{
delegate D D();
delegate E E();
delegate U V();
delegate V U();
static void Main()
{
D d = null, du = null, dv = null;
d = () => d;
du = () => du;
dv = () => dv;
U u = null; V v = null;
u = () => v;
v = () => u;
}
}
现在我们回过头来看,如果用签名等价的委托类型思想,E
、D
、U
、V
都是 T = Func<Func<T>>
的解。而且 E
、D
都是 T = Func<T>
的解。
用数学的观点看,若 把 映为 ,则 已经没法表示成集合(映射是集合间的一种特别的关系)的样子了,对于我(没有学习过类型论、集合论)来说,这太难以分析了。(注:要证明 不是集合,只要注意到集合不能拥有自己,也不能拥有拥有自己的集合,也不能拥有拥有拥有自己的集合。)
另一种理解为什么签名相同的委托不是同一个类型的别名,可以参见 vczh 的评论:
delegate Fuck Fuck();
等价于 Java 中的interface Fuck { Fuck Invoke(); }
同理,我们很难说
interface I1
{
int Invoke();
}
interface I2
{
int Invoke();
}
定义了同一个接口。此外,在 C# 里面你可以做 C++ 里面 std::function
模板做不到的事情(例如 E
、D
、U
、V
这几个类型没法写成有限的 std::function
模板实例化,除非再定义一个可以转换到 std::function
的具名类型),因此也没有理由默认委托只是函数签名。
请启用 JavaScript 来查看由 Disqus 驱动的评论。