C#委托与lambda表达式的逆变

C#委托与lambda表达式的逆变,c#,delegates,lambda,contravariance,method-group,C#,Delegates,Lambda,Contravariance,Method Group,下面的第二个测试方法未编译(无法将lambda表达式转换为目标类型D1)。这是否意味着(非泛型)委托逆变不适用于lambda表达式 [TestFixture] public class MyVarianceTests { private abstract class Animal {} private class Tiger : Animal {} private delegate Type D1(Tiger tiger); private static Ty

下面的第二个测试方法未编译(无法将lambda表达式转换为目标类型
D1
)。这是否意味着(非泛型)委托逆变不适用于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));
    }
}

D1排除了老虎类型的论点,但你传递的是一种动物。 动物不是老虎
但是老虎是一种动物

你发现了语言上的不一致

这在以下文件中明确指出:

7.15.1匿名函数签名

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

…这就提出了一个问题:

为什么语言设计人员不支持此功能?

显然,该功能有一些小的好处。但是,它是否证明了兼容编译器实现所需的额外复杂性的成本是合理的

编写lambda表达式时,您必须已经确切地知道它要转换为哪种委托/表达式树类型(没有可以“保存”任意lambda的通用类型)。从C#5开始,lambda(与方法相反)除了帮助创建单个委托/表达式树实例之外,完全没有其他用途。因此,显式指定一个比参数所需的更通用的类型并期望编译器提供相反的支持并没有任何好处(除了方便)。您可以完全省略该类型并依赖于类型推断(或者,在最坏的情况下,显式指定所需的确切参数类型),而不损失任何可重用性或可表达性

这显然不适用于方法,这些方法除了用于创建委托/表达式树之外,还有其他用途。您可能需要一个特定的函数签名(不同于委托的),因为它是最合适的,或者需要它,因为它必须满足接口约定。此外,考虑到在创建方法组转换时,(作为创建委托/表达式树的程序员)不一定“拥有”所讨论的方法(它可能在第三方程序集中)。兰博达斯的情况从来就不是这样

与方法组不同,语言设计人员似乎觉得为lambdas实现参数类型的逆变的好处并不能证明成本是合理的


动物没有那么具体,因此将一个接受
动物的函数分配给一个指定
老虎的代理应该不会有问题<代码>M1
D1
更具体。是 啊协方差和反方差通常令人难以置信,并且不像你第一次直观地想到的那样工作。你的答案如何不适用于方法组转换
D1 func=M1?Ani是正确的。这个答案没有考虑语句
D1 func=M1按预期工作。谢谢,这是我正在寻找的参考资料。你对为什么会有不一致的猜测对我来说也是有意义的。