C#委托与lambda表达式的反演

下面的第二个测试方法不编译(不能将lambda表达式转换为目标类型D1 )。 这是否意味着(非generics)委托契约不适用于lambda表达式?

 [TestFixture] public class MyVarianceTests { private abstract class Animal {} private class Tiger : Animal {} private delegate Type D1(Tiger tiger); private static Type M1(Animal animal) { return animal.GetType(); } [Test] public void ContravariantDelegateWithMethod() { D1 func = M1; Type result = func(new Tiger()); Assert.AreEqual(result, typeof (Tiger)); } [Test] public void ContravariantDelegateWithLambda() { D1 func = (Animal animal) => animal.GetType(); Type result = func(new Tiger()); Assert.AreEqual(result, typeof (Tiger)); } } 

您已经确定了该语言的不一致性。

这在语言规范中明确调出:

7.15.1匿名function签名

[…]与方法组转换(第6.6节)相比,不支持匿名函数参数类型的反方差。 […]

……提出了一个问题:

为什么语言设计师不支持这个function呢?

显然,该function有一些小的好处。 但它是否certificate合规编译器实现所需的额外复杂性的成本是合理的?

当你编写一个lambda表达式时,你必须已经确切地知道它被转换为哪个委托/表达式树类型(没有可以“保持”任意lambda的通用类型)。 从C#5开始,lambda(与方法相反)除了帮助创建单个委托/表达式树实例之外,完全没有用处。 因此, 明确指定比参数所需的更通用的类型并期望来自编译器的反方差支持没有优势(除了方便)。 您可以完全省略类型并依赖类型推断(或者,最坏的情况,明确指定所需的确切参数类型),而不会丢失可重用性或可表达性。

这显然不适用于除了创建委托/表达式树之外的其他目的的方法。 您可能需要特定的函数签名(不同于委托),因为它是最合适的,或者需要它,因为它必须满足接口契约。 此外,考虑到您(作为创建委托/表达式树的程序员)在执行方法组转换时不一定“拥有”有问题的方法(可能在第三方程序集中)。 lambda不是这种情况。

看起来语言设计者认为实施lambdas参数类型的反差方法的好处并不能certificate成本是合理的,这与方法组不同。

D1除了Tiger类型的参数外,你传递的是一种类型的Animal。 动物不是老虎但虎是动物