有人可以解释为什么需要添加 out 或 in 参数来指示泛型类型是 C# 4.0 中的 Co 或 Contra 变体吗?
我一直在试图理解为什么这很重要以及为什么编译器不能弄清楚..
谢谢,
乔什
有人可以解释为什么需要添加 out 或 in 参数来指示泛型类型是 C# 4.0 中的 Co 或 Contra 变体吗?
我一直在试图理解为什么这很重要以及为什么编译器不能弄清楚..
谢谢,
乔什
从事语言工作的 Eric Lippert 在 msdn 上有一系列帖子,应该有助于澄清所涉及的问题:http:
//blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
阅读该链接上显示的文章时,请从底部开始并逐步进行。
最终你会得到#7(为什么我们需要语法?)。
我们实际上并不需要它们,不再需要abstract
类或两者out
兼而有之ref
。它们的存在只是为了让我们作为程序员可以清楚地表达我们的意图,以便维护程序员知道我们在做什么,并且编译器可以验证我们是否做对了。
好吧,主要问题是,如果您有一个类层次结构,例如:
class Foo { .. }
class Bar : Foo { .. }
而且你有一个IEnumerator<Bar>
,你不能把它用作一个,IEnumerator<Foo>
即使那是非常安全的。在 3.5 中,这会导致大量痛苦的旋转。这个操作总是安全的,但被类型系统拒绝,因为它不知道泛型类型参数的协变使用。IEnumerator<Bar>
只能返回 aBar
并且everyBar
是 a Foo
。
同样,如果您有 anIEqualityComparer<Foo>
它可以用于比较任何类型的对象,Foo
即使其中一个或两个都是 a Bar
,但它不能转换为 anIEqualityComparer<Bar>
因为它不知道泛型类型参数的逆变使用。IEqualityComparer<Foo>
仅消耗类型的对象,Foo
并且每个Bar
都是Foo
.
如果没有这些关键字,我们就不得不假设泛型参数既可以作为方法的参数出现,也可以作为方法的结果类型出现,因此我们不能安全地允许上述任何一种转换。
有了它们,类型系统就可以自由地允许我们在这些接口之间按照关键字指示的方向安全地向上转换和向下转换,并且我们会得到错误,表明我们何时会违反确保安全所需的规则。
in
and关键字自 C# 1.0 以来一直是关键字,out
并且已在方法的in
- 和out
- 参数的上下文中使用。
协变和逆变是对如何实现接口的约束。没有很好的方法来推断它们——我认为唯一的方法是从使用中,这会很混乱,最终它不会起作用。
Jon 和 Joel 都对此提供了非常完整的答案,但最重要的是编译器并不需要它们,而是通过显式指示参数的变化来帮助保证实现的安全性。这与在调用站点和声明站点都需要out
or关键字的模式非常相似。ref