问题描述
下面的第二种测试方法无法编译(无法将 lambda 表达式转换为目标类型 D1
).这是否意味着(非泛型)委托逆变不适用于 lambda 表达式?
The second test method below does not compile (cannot convert lambda expression to target type D1
). Does that mean that (non-generic) delegate contravariance does not work with lambda expressions?
[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 匿名函数签名
[...] 与方法组转换(第 6.6 节)相比,匿名函数的逆变不支持参数类型.[...]
[...] In contrast to method group conversions (§6.6), contra-variance of anonymous function parameter types is not supported. [...]
...这就提出了一个问题:
...which raises the question:
为什么语言设计者不费心支持这个功能?
<推测>
显然,该功能有一些小好处.但这是否证明了合规编译器实现所需的额外复杂性的成本是合理的?
Clearly, the feature has some small benefits. But does it justify the costs of the extra complications required in a compliant compiler implementation?
当您编写一个 lambda 表达式时,您必须已经确切知道它被转换为哪种委托/表达式树类型(没有通用类型可以保存"任意 lambda).从 C# 5 开始,lambda(与方法相反)除了帮助创建 single 委托/表达式树实例外,完全没有其他用途.因此,明确指定比参数所需的更通用的类型并期望编译器提供逆变器支持没有任何优势(除了方便).您可以完全省略类型并依赖类型推断(或者,在最坏的情况下,明确指定所需的确切参数类型),而不会损失可重用性或可表达性.
When you write a lambda expression, you must already know exactly which delegate/expression-tree type it is being converted to (there's no general-purpose type that can "hold" an arbitrary lambda). As of C# 5, a lambda (in contrast to a method) serves absolutely no purpose other than to help in the creation of a single delegate / expression-tree instance. Consequently, there's no advantage (other than convenience) to explicitly specifying a more general type than required for a parameter and expecting contra-variance support from the compiler. You could just omit the type completely and rely on type-inference (or, worst case, explicitly specify the exact parameter-type required) without any loss in reusability or expressibility.
这显然不适用于方法,这些方法除了创建委托/表达式树之外还有其他用途.您可能需要一个特定的函数签名(不同于委托的),因为它是最合适的,或者需要它,因为它必须满足接口契约.此外,考虑到您(作为创建委托/表达式树的程序员)不一定拥有"当您执行方法组转换时,有问题的方法(它可能在第三方程序集中).lambdas 从来都不是这种情况.
This obviously doesn't apply to methods, which serve other purposes other than the creation of delegates/expression-trees. You may desire a particular function signature (different from the delegate's) because it is the most appropriate, or require it because it must satisfy an interface contract. Further more, consider that you (as the programmer creating the delegate/expression-tree) don't necessarily "own" the method in question (it could be in a third-party assembly) when you are performing a method-group conversion. This is never the case with lambdas.
与方法组不同,语言设计者似乎认为为 lambda 实现参数类型逆变的好处并不能证明成本是合理的.
It appears the language-designers felt the benefits of implementing contra-variance of parameter types for lambdas didn't justify the costs, unlike for method-groups.
</speculation>
这篇关于C# 委托逆变与 lambda 表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!