论接口的协变性和逆变性

posted at 2017.10.22 21:36 by 风信子

协变性和逆变性在泛型世界中似乎是一个边缘化的主题,但它们实际上是相当有意义的。例如,List<T>泛型集合类使用ICompare<T>对象实现SortBinarySearch方法。

一个List<Object>对象可以包含任何类型的对象的一个集合,所以SortBinarySearch方法要求能对任何类型的对象进行排序。如果不使用逆变,SortBinarySearch方法就需要添加逻辑来判断要排序或搜索的数据项的真实类型,然后实现一个依赖于特定类型的排序或搜索机制。

当然,协变性和逆变性这两个个词确实难以理解,刚开始可能搞不清楚两者的作用。

可以这样记忆它们:

协变性(Covariance)  如果泛型接口中的方法能返回字符串,它们也能返回对象。(所有字符串都是对象。)

          逆变性(Contravariance) 如果泛型接口中的方法能获取对象参数,它们也能获取字符串参数。(用一个对象能执行的操作,用字符串同样能;因为所有字符串都是对象。)

UPS电源原理图

当然,只有接口和委托类型能声明为协变量或逆变性。不能为泛型,类使用inout修饰符。

定义协变接口   

为协变类型参数指定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的一个对象。

 

Tags: , , ,

IT技术 | 观察评论

添加评论

  Country flag

biuquote
  • 评论
  • 在线预览
Loading