为什么我们需要在C#中使用协方差和反差异的新关键字?
-
06-07-2019 - |
题
有人可以解释为什么需要在C#4.0中添加out或in参数来表示泛型类型是Co或Contra变种吗?
我一直在努力理解为什么这很重要,为什么编译器不能只想出来......
谢谢,
约什
解决方案
负责语言工作的Eric Lippert在msdn上发布了一系列帖子,这些帖子应该有助于澄清所涉及的问题:
http://blogs.msdn.com/ericlippert/存档/标签/协方差+和+逆变/ Default.aspx的
阅读该链接中显示的文章时,请从底部开始处理。
最终你会得到#7(为什么我们需要语法?)。
其他提示
我们实际上不需要它们,然后我们需要abstract
对类或out
和ref
两者。它们的存在只是为了让我们作为程序员能够清楚地表达我们的意图,以便维护程序员知道我们在做什么,并且编译器可以验证我们做得对。
好吧,主要的问题是如果你有一个类层次结构,如:
class Foo { .. }
class Bar : Foo { .. }
你有一个IEnumerator<Bar>
,你不能将它作为IEnumerator<Foo>
使用,即使这是非常安全的。在3.5中,这会导致大量痛苦的回转。此操作始终是安全的,但类型系统拒绝该操作,因为它不知道泛型类型参数的协变使用。 Bar
只能返回Foo
,而每个IEqualityComparer<Foo>
都是IEqualityComparer<Bar>
。
同样,如果你有一个<=>它可以用来比较任何一对<=>类型的对象,即使其中一个或两个都是<=>,但它不能被转换成<=>,因为它不知道泛型类型参数的逆变使用。 <=>仅使用<=>类型的对象,并且每个<=>都是<=>。
如果没有这些关键字,我们不得不假设泛型参数可以作为方法的参数和方法的结果类型出现,因此我们无法安全地允许上述任何一种转换。
有了它们,类型系统可以自由地允许我们按照关键字指示的方向安全地在这些接口之间进行向上和向下转换,并且我们会收到错误,指出我们何时会违反确保安全所需的纪律。
in
和out
关键字是自C#1.0以来的关键字,并且已在<=> - 和<=> - 方法的参数中使用。
协方差和逆变是对如何实现接口的约束。没有什么好的方法来推断它们 - 我认为唯一的方法是使用,这将是混乱的,最终它将无法工作。
Jon和Joel都为此提供了一个非常完整的答案,但最重要的是编译器并没有那么多需要,而是通过明确指示来帮助保证实现的安全性参数的方差。这与在调用站点和声明站点上要求out
或ref
关键字的模式非常相似。