重要更新:由于 优快云 Live Writer 发布系统存在严重缺陷,导致将泛型接口误判断为标记,因此本文有一部分内容无法显示。需要阅读本文的读者,请关于 www.markzhou.com,我们尽快为您做镜像。谢谢大家配合!
Covariance 是一种运行时类型转换。我们可能会遇到这样的事情,就是在一些使用了泛型的接口或者数组中,即使只有泛型参数的类型不同,这些类型也不能像普通类一样互相转换。例如在 C# 3.0 中,将一个 System.Int32[] 转换成 System.Object[] 是不可能的。看下面的代码。
另外一个例子关于泛型接口的。看下面的代码:
编译器给出无法转换 I<A> 和 I<B> 的错误。其实,B 是 A 的派生类型,也就是说理论上从 B 转换为 A 是有可能的;但将它作为泛型接口的类型参数后,则无法对接口中的泛型类型进行转换了。
那么我们怎么解决这个问题呢?我们需要一种运行时检查和转换机制,以便处理类型参数以及数组元素之间的动态类型转换问题。
什么是 Covariance
Covariance 用于数组、泛型接口和泛型委托中,如果存在泛型接口 I<T> 的两个实例 I<A> 和 I<B>,而 A 和 B 之间有继承关系,且 A > B。如果允许 I<B> 隐式转换为 I<A>,则成 I<T> 支持 Covariance。
那么什么叫作 A > B?通俗的讲,也就是 A 出现在继承树的更上层;因为 A 处在更加抽象的地方,因此 A 更加泛化,也就是说 A 比处在低处的 B 更大。例如,Object 最大;Form 比 Compoment 小(因为 Form 继承自 Compoment) 等。
支持 Covariance 的类型可以表示为:I<T+>,或者 I<out T>。
数组类型的 Covariance
因为数组的实际类型是引用类型,因此在数组之间的类型转换包含一些规则。
对于任何两个引用类型 A 和 B,当 A 和 B 之间存在引用或者数组转换,则在相同上下标的数组转换就会存在。这种关系称之为数组的 Covariance。一个数组 Covariance 意味着类型 A 的引用实际上就是 B 的类型。如果我们希望从 System.String[] 到 System.Object[] 的隐式转换,那么在运行时,我们需要一些约束来确定这两个类型是完全兼容的。在下面的例子里面我们会得到一个 System.ArrayTypeMismatchException,因为 b 的实际类型是 String,而不是 Object。
因为存在数组的 Covariance,因此试图对数组元素赋值时就存在一个运行时检查,以确保右值是一个可被接受的类型实例。
同样的转换还出现在枚举类型和数组之间。下面的例子描述了一个基于 byte 的枚举与数组之间的 Covariance。
这个例子中,b = a 是无效的,因为 b 的元素类型是 int,而不是 byte。
下一次,我们向大家介绍接口的 Covariance。