【问题标题】:Why does C#/CLR not support method override co/contra-variance?为什么 C#/CLR 不支持方法覆盖协/逆变?
【发布时间】:2010-10-24 15:23:11
【问题描述】:

有很多关于破解 C# 的限制的问题和答案,不允许将方法返回(和参数)类型更改为覆盖时的兼容类型,但为什么存在此限制,在 C# 编译器中还是在 CLR 中?正如我所见,如果允许协方差,就没有什么可以破坏的,那么它背后的原因是什么?

类似的问题可能会被问到扩大访问参数 - 例如用公共方法(Java支持的东西,IIRC)覆盖受保护的内部方法

【问题讨论】:

    标签: c# .net clr overriding covariance


    【解决方案1】:

    Eric Lippert 已经比我更好地回答了这个问题。

    Covariance and Contravariance in C#查看他的系列

    How does C# 4.0 Generic Covariance & Contra-variance Implmeneted?

    编辑:Eric 指出他没有谈论返回类型协变,但我决定保留此答案中的链接,因为这是一个很酷的系列文章,如果查找此主题,有人可能会发现它很有用。

    这个功能是requested,大约 5 年前,微软已经回复了“感谢您记录这个。我们经常听到这个请求。我们会在下一个版本中考虑它。”

    现在我将引用 Jon Skeet 的话,因为如果没有 Jon Skeet 的回答,这将不是 StackOverflow 上的正确答案。 Covariance and void return types

    我强烈怀疑答案 在于CLR的实现 而不是任何深层语义 原因 - CLR 可能需要 知道是否有 是一个返回值,为了做 适当的东西与堆栈。 即便如此,似乎还是有点遗憾,在 优雅的术语。我不能说我已经 曾经真正感觉到需要这个 生活,这将相当容易 伪造(最多四个参数) .NET 3.5 只需编写转换器 从Func<X>Action<X>Func<X,Y>Action<X,Y> 等。它有点琐碎 虽然:)

    【讨论】:

    • 我知道 implmenedted 拼写错误。但我只是直接链接到它。
    • 不,我从未回答过这个问题。这些文章是关于泛型类型差异的。这个问题是关于返回类型协方差的。在我关于泛型方差的文章中,我明确指出我不是在谈论返回类型方差。
    • 哦。我失败的记忆。我几个月前阅读了它们,并且在发布此答案之前没有重新阅读它们。 :)
    • 再一次,我不是指 void 和其他对象类型之间的协方差,我指的是方法覆盖的协方差 - 用返回字符串的方法覆盖返回对象的方法
    【解决方案2】:

    这个答案不是在谈论 C#,但它帮助我更好地理解了这些问题,也许它会帮助其他人:Why is there no parameter contra-variance for overriding?

    【讨论】:

      【解决方案3】:

      引入返回值协方差的接缝没有 Java 和 C++ 使用过的本质缺陷。但是,引入形式参数的逆变会引起真正的混乱。我认为 C++ 中的这个答案https://stackoverflow.com/a/3010614/1443505 也适用于 C#。

      【讨论】:

        【解决方案4】:

        确实如此,你只需要等待VS2010/.Net 4.0。

        【讨论】:

        • 这只是接口的情况,而不是具体类型
        • 但是最初忽略它的原因是什么?这似乎是一个非常有用的东西,例如对于工厂模式
        • @JaredPar - 接口 + 委托 ;-p
        • “但最初将其排除在外的原因是什么?”见:blog.ryjones.org/2005/07/12/product-development
        • 这是不正确的。 C# 4.0 不添加返回类型协方差。我们添加了泛型类型差异,这是完全不同的。
        【解决方案5】:

        为了扩展 Joel 的答案 - CLR 长期以来一直支持有限的变化,但 C# 编译器直到 4.0 才使用它们,并在通用接口和委托上使用新的“in”和“out”修饰符。原因很复杂,我会陷入混乱试图解释,但它并不像看起来那么简单。

        将“受保护的内部”方法重新制作为“公共”方法;你可以通过隐藏方法来做到这一点:

        public new void Foo(...) { base.Foo(...); }
        

        (只要参数等都是公开的)- 有什么用吗?

        【讨论】:

        • 是的,CLR 2 支持泛型类型变化。但它不支持返回类型协方差。
        • 方法隐藏会起作用,但它不会像虚拟方法一样 - 对超类型实例的调用不会被调度到公共覆盖
        • 确实;它有局限性......而且因为你不能覆盖和“新”相同类型的相同签名,除非你引入一个 extra 类型和一个 ,否则你无法实现正确的虚拟额外的虚拟通话。
        • 错误答案。泛型方差!=覆盖方差;方法隐藏!=覆盖
        猜你喜欢
        • 2018-12-24
        • 1970-01-01
        • 1970-01-01
        • 2018-02-22
        • 1970-01-01
        • 1970-01-01
        • 2017-08-13
        • 1970-01-01
        相关资源
        最近更新 更多