有很多关于破解 C# 的限制的问题和答案,不允许方法返回(和参数)类型在覆盖时更改为兼容类型,但为什么在 C# 编译器或 CLR 中存在此限制?如我所见,如果允许协方差,没有什么可以破坏的,那么它背后的原因是什么?
可以询问类似的问题来扩大访问参数 - 例如用公共方法覆盖受保护的内部方法(Java支持的东西,IIRC)
有很多关于破解 C# 的限制的问题和答案,不允许方法返回(和参数)类型在覆盖时更改为兼容类型,但为什么在 C# 编译器或 CLR 中存在此限制?如我所见,如果允许协方差,没有什么可以破坏的,那么它背后的原因是什么?
可以询问类似的问题来扩大访问参数 - 例如用公共方法覆盖受保护的内部方法(Java支持的东西,IIRC)
Eric Lippert 已经比我更好地回答了这个问题。
查看他关于C# 中的协变和逆变的系列文章
和
C# 4.0 Generic Covariance & Contra-variance 是如何实现的?
编辑:埃里克指出他没有谈论返回类型的协变,但我决定在这个答案中保留链接,因为这是一个很酷的系列文章,如果查找这个主题,有人可能会发现它很有用。
此功能已被请求,大约 5 年前,Microsoft 已回复“感谢您记录此功能。我们经常听到此请求。我们将在下一个版本中考虑它。”
现在我将引用 Jon Skeet,因为如果没有 Jon Skeet 的回答,它就不是 StackOverflow 上的正确答案。协方差和 void 返回类型
我强烈怀疑答案在于 CLR 的实现,而不是任何深层的语义原因 - CLR 可能需要知道是否会有返回值,以便对堆栈执行适当的操作。即便如此,就优雅而言,这似乎有点可惜。我不能说我在现实生活中曾经觉得需要这样做,而且只需编写一个从
Func<X>
to 到 to等的转换器Action<X>
,在 .NET 3.5 中伪造(最多四个参数)是相当容易的。它很琐碎虽然有点:)Func<X,Y>
Action<X,Y>
这个答案不是在谈论 C#,但它帮助我更好地理解了这些问题,也许它会帮助其他人:为什么没有用于覆盖的参数逆变?
引入返回值协方差的 Seams 没有 Java 和 C++ 使用过的本质缺陷。然而,引入形式参数的逆变会引起真正的混乱。我认为 C++ 中的这个答案https://stackoverflow.com/a/3010614/1443505也适用于 C#。
确实如此,您只需要等待 VS2010/.Net 4.0。
为了扩展 Joel 的答案 - CLR 长期以来一直支持有限的变化,但 C# 编译器直到 4.0 才使用它们,并在通用接口和委托上使用新的“in”和“out”修饰符。原因很复杂,我会陷入混乱试图解释,但这并不像看起来那么简单。
将“受保护的内部”方法重新制作为“公共”方法;你可以通过隐藏方法来做到这一点:
public new void Foo(...) { base.Foo(...); }
(只要论点等都是公开的) - 有什么用吗?