C# 4.0 新特性 -- Covariance 2: 接口和委托的 Covariance

本文深入探讨了C#中的Covariance概念,包括其在泛型接口和委托中的应用,以及如何通过out约束来实现类型转换。同时,还讨论了.NET Framework 4.0中对Covariance的支持。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇文章我们介绍了基于数组的 Covariance,数组的 Covariance 是一个隐含的类型转换,但很可惜这个隐含转换并不适用于接口以及委托。如果在接口和委托中存在类型参数,而希望从一个泛型接口转换成另外一个泛型接口,或者委托之间的转换的话,必须要引入泛型接口和委托的 Covariance。

我们说过了,Covariance 允许这样的类型转换:如果存在类 A 和 B,A 是 B 的基类(A > B),那么 I<T> 是一个泛型接口,T 约束为 A(where T : A),那么从类型 I<B> 可以转换为类型 I<A>。

对于委托,如果存在类 A 和 B,A 是 B 的基类(A > B),那么 D<T>() 是一个泛型委托,T 约束为 A(where T : A),那么从委托 D<B> 可以转换为委托 D<A>。

如何声明一个接口或者委托支持 Covariance

C# 4.0 现在提供一个新的约束性语法,在声明返型接口或委托时,可以在泛型参数前面加上 in 或者 out 来表示该接口或委托支持 Contra-variance 或 Covariance。这篇文章只涉及到 Covariance,因此我们需要一个 out 约束。

某一些 CLR 系统内置的类,如 IEnumerable<T>,已经被声明成了 IEnumerable<out T>。我们通过 Metadata 看到的 System.Collections.Generic.IEnumerable<T> 如下。

image

这就意味着 .NET Framework 4.0 中的 IEnumerable<T> 支持 Covariance。于是,下面的代码是可以工作的 。

image

我们也可以自己实现 Covariance。如下面的例子,类 A  和 类 B 具备继承关系,下面的转换都是合法的。因为 object > A > B,因此 B –> A,B –> object 以及 A –> object 均有效。

image

Covariance 的约束条件

按照惯例,不是所有具备泛型参数的接口和委托都可以用来支持 Covariance。如果类型 I<T> 或委托 D<T> 的类型参数 T 具备 out 约束,那么:

  • T 是类、结构或者枚举类型。
  • T 是非泛型接口或者委托类型。
  • T 是元素类型支持 Variance 的数组。
  • T 是一个没有被定义为 out 约束的类型参数类型。

另外,支持 Covariance (有 out 约束)的泛型接口或委托存在以下限制:

  • 他们不能包含一个具备类型参数表的事件(但自定义事件或者使用委托声明的事件除外)。
  • 他们不能包含内部类(Nested Class)、结构或枚举类型。

其他需要注意的地方

作为最佳实践,泛型接口的类型参数 T 一般为 out 约束(Covariance),泛型委托的类型参数如果是作为参数列表的,则一般为 in 约束(Contra-variance),而类型参数作为返回值的,一般为 out 约束(Covariance)。关于这一点请参照 IEnumerable<out T> 和 Func<in T, out TResult>。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值