C# 4.0 新特性 – Covariance 1: 数组 Covariance

本文介绍了Covariance的概念及其在数组、泛型接口和泛型委托中的应用。通过具体示例展示了不同类型之间的转换问题,并探讨了解决方案。

重要更新:由于 优快云 Live Writer 发布系统存在严重缺陷,导致将泛型接口误判断为标记,因此本文有一部分内容无法显示。需要阅读本文的读者,请关于 www.markzhou.com,我们尽快为您做镜像。谢谢大家配合!

Covariance 是一种运行时类型转换。我们可能会遇到这样的事情,就是在一些使用了泛型的接口或者数组中,即使只有泛型参数的类型不同,这些类型也不能像普通类一样互相转换。例如在 C# 3.0 中,将一个 System.Int32[] 转换成 System.Object[] 是不可能的。看下面的代码。

image

另外一个例子关于泛型接口的。看下面的代码:

image

编译器给出无法转换 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。

image

image

因为存在数组的 Covariance,因此试图对数组元素赋值时就存在一个运行时检查,以确保右值是一个可被接受的类型实例。

同样的转换还出现在枚举类型和数组之间。下面的例子描述了一个基于 byte 的枚举与数组之间的 Covariance。

image

这个例子中,b = a 是无效的,因为 b 的元素类型是 int,而不是 byte。

下一次,我们向大家介绍接口的 Covariance。

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <display-name>AirlineBooking</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- 配置JSTL --> <jsp-config> <taglib> <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri> <taglib-location>/WEB-INF/lib/jstl-1.2.jar</taglib-location> </taglib> </jsp-config> <filter> <filter-name>AuthFilter</filter-name> <filter-class>com.airline.filter.AuthFilter</filter-class> </filter> <filter-mapping> <filter-name>AuthFilter</filter-name> <url-pattern>/booking/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>AuthFilter</filter-name> <url-pattern>/user/*</url-pattern> </filter-mapping> <!-- <!&ndash; 应用显示名称 &ndash;>--> <!-- <display-name>OnlineShop</display-name>--> <!-- <!&ndash; 欢迎文件列表 &ndash;>--> <!-- <welcome-file-list>--> <!-- <welcome-file>index.jsp</welcome-file>--> <!-- </welcome-file-list>--> <!-- <!&ndash; 会话超时配置(单位:分钟) &ndash;>--> <!-- <session-config>--> <!-- <session-timeout>30</session-timeout>--> <!-- </session-config>--> <!-- <!&ndash; Servlet 配置 &ndash;>--> <!-- <servlet>--> <!-- <servlet-name>LoginServlet</servlet-name>--> <!-- <servlet-class>com.onlineshop.servlet.LoginServlet</servlet-class>--> <!-- </servlet>--> <!-- <servlet>--> <!-- <servlet-name>RegisterServlet</servlet-name>--> <!-- <servlet-class>com.example.onlineshop.servlet.RegisterServlet</servlet-class>--> <!-- </servlet>--> <!-- <!&ndash; Servlet 映射 &ndash;>--> <!-- <servlet-mapping>--> <!-- <servlet-name>LoginServlet</servlet-name>--> <!-- <url-pattern>/login_process.jsp</url-pattern>--> <!-- </servlet-mapping>--> <!-- <servlet-mapping>--> <!-- <servlet-name>RegisterServlet</servlet-name>--> <!-- <url-pattern>/register_process.jsp</url-pattern>--> <!-- </servlet-mapping>--> <!-- <!&ndash; 错误页面配置 &ndash;>--> <!--<!&ndash; <error-page>&ndash;>--> <!--<!&ndash; <error-code>404</error-code>&ndash;>--> <!--<!&ndash; <location>/error/404.jsp</location>&ndash;>--> <!--<!&ndash; </error-page>&ndash;>--> <!--<!&ndash; <error-page>&ndash;>--> <!--<!&ndash; <error-code>500</error-code>&ndash;>--> <!--<!&ndash; <location>/error/500.jsp</location>&ndash;>--> <!--<!&ndash; </error-page>&ndash;>--> <!-- <!&ndash; 上下文参数 &ndash;>--> <!-- <context-param>--> <!-- <param-name>jdbcDriver</param-name>--> <!-- <param-value>com.mysql.jdbc.Driver</param-value>--> <!-- </context-param>--> <!-- <context-param>--> <!-- <param-name>jdbcUrl</param-name>--> <!-- <param-value>jdbc:mysql://localhost:3306/onlineshop</param-value>--> <!-- </context-param>--> <!-- <!&ndash; 过滤器配置(可选) &ndash;>--> <!--<!&ndash; <filter>&ndash;>--> <!--<!&ndash; <filter-name>CharacterEncodingFilter</filter-name>&ndash;>--> <!--<!&ndash; <filter-class>com.example.onlineshop.filter.CharacterEncodingFilter</filter-class>&ndash;>--> <!--<!&ndash; <init-param>&ndash;>--> <!--<!&ndash; <param-name>encoding</param-name>&ndash;>--> <!--<!&ndash; <param-value>UTF-8</param-value>&ndash;>--> <!--<!&ndash; </init-param>&ndash;>--> <!--<!&ndash; </filter>&ndash;>--> <!--<!&ndash; <filter-mapping>&ndash;>--> <!--<!&ndash; <filter-name>CharacterEncodingFilter</filter-name>&ndash;>--> <!--<!&ndash; <url-pattern>/*</url-pattern>&ndash;>--> <!--<!&ndash; </filter-mapping>&ndash;>--> </web-app>我这个配置有问题吗
最新发布
06-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值