C# 使用 lambda 表达式委托(delegate)逆变

标签 c# delegates lambda contravariance method-group

<分区>

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

最佳答案

您发现了语言中的不一致。

这在 language specification 中明确指出:

7.15.1 Anonymous function signatures

[...] In contrast to method group conversions (§6.6), contra-variance of anonymous function parameter types is not supported. [...]

...这提出了问题:

为什么语言设计者不支持这个特性?

<speculation>

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

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

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

看起来语言设计者认为,与方法组不同,为 lambda 实现参数类型的逆变的好处并不能证明成本是合理的。

</speculation>

关于C# 使用 lambda 表达式委托(delegate)逆变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37111617/

相关文章:

c# - 泛型委托(delegate)声明中 'in, out'的含义

.net - 在 .NET 中,为什么事件连接顺序如此重要?

python按值排序json列表

c++ - 在 C++ lambda 函数中传递 >1 个 vector 的方法

c# - 使用 autofac 在 global.asax 中解析或注入(inject)依赖项

IOS Swift,委托(delegate)在两个 View Controller 之间进行通信

c# - 使用 C#/WPF 显示缩略图网格

c++ - 当我将 lambda 表达式复制到 std::function 时出了什么问题

c# - cURL 发布到 HTTPCLient C#

c# - COM对象失败,类未注册错误,WMEncBasicEdit