posted at 2017.10.22 21:36 by 风信子
协变性和逆变性在泛型世界中似乎是一个边缘化的主题,但它们实际上是相当有意义的。例如,List<T>泛型集合类使用ICompare<T>对象实现Sort和BinarySearch方法。
一个List<Object>对象可以包含任何类型的对象的一个集合,所以Sort和BinarySearch方法要求能对任何类型的对象进行排序。如果不使用逆变,Sort和BinarySearch方法就需要添加逻辑来判断要排序或搜索的数据项的真实类型,然后实现一个依赖于特定类型的排序或搜索机制。
当然,协变性和逆变性这两个个词确实难以理解,刚开始可能搞不清楚两者的作用。
可以这样记忆它们:
协变性(Covariance) 如果泛型接口中的方法能返回字符串,它们也能返回对象。(所有字符串都是对象。)
逆变性(Contravariance) 如果泛型接口中的方法能获取对象参数,它们也能获取字符串参数。(用一个对象能执行的操作,用字符串同样能;因为所有字符串都是对象。)
当然,只有接口和委托类型能声明为协变量或逆变性。不能为泛型,类使用in或out修饰符。
定义协变接口
为协变类型参数指定out限定符。协变量泛型类型参数只能出现在输出位置,比如作为方法的返回类型。不能作为方法的参数类型。
示例如下:
Interface IRetrieveWrapper<out T>
{
T GetData ();
}
只要存在从类型A到类型B的一个有效转换,或者类型A派生自类型B,就可以将一个-个IRetrieveWrapper<A>对象赋给一个IRetrieveWrapper<B>引用。另外,协变性只适用于引用类型,因为值类型不能建立继承层次结构。
定义逆变接口
为逆变类型参数指定in限定符。逆变量泛型类型参数只出现在输入位置,比如作为方法的参数。不能作为方法的返回类型。
示例如下:
Public interface IComparer<in T>
{
Int Compare (T x,T y));
}
in关键字明确告诉C#编译器,你要么传递T作为方法的参数类型,要么传递从T派任何类型。T不能作为任何方法的返回类型使用。乏型接口来引用。简单地说,如果类型A公开了一些操作、属性或字段,那么从类型A派生出类型B时,B也肯定会公开同样的操作(如果重写这些操作,它们允许有不同的行为)、属性和字段。因此,可以安全地用类型B的一个对象来替换类型A的一个对象。
f8e7ad1d-5704-4d3e-9cb3-400093c9bd24|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04
Tags: 泛型, 接口, 类, c#
IT技术 | 观察评论