泛型在.NET 2.0中正式的引入。在使用泛型的过程中,联系上面向对象的继承性。往往很容易想当然敲出类似以下代码
List<Animal> animalLst=new List<Dog>;
显然这样编译是不通过的。虽然Dog和Animal之间有继承性,但是List<Animal>和List<Dog>这两个类之间并没有继承性。如果要解决这样的问题,用上协变与抗变(逆变),它们统称为变体。是.NET 4.0引入的新特性,但是早在.NET 2.0就引入了。
变体适用于泛型接口与泛型委托,在我们声明泛型借口或泛型委托时,加上out或in关键字就能实现。
两者可以说得上是用于整条类的继承链上转换工作的,但是方向不同。
那么先来看看协变
delegate T AnimalAction1<out T>(); interface IProduce<out T> { T TypeIns { get; } T CreteNewTypeIns(); }
out这个关键字使人联想到“输出”,既然是出的话,那么协变的类型只能用于方法的返回值或者是属性的get,如果变量作为方法的参数(即使是带out关键字的参数)和属性的set,那么编译会报错。那么在FCL里面是协变的接口和委托如下
IQueryable<out T> IEnumerator<out T> IGrouping<out TKey,out TElement> Converter<in TInput,out TOutput>
看上去都是返回泛型T的。
再看看抗变
delegate void AnimalBark<in T>(T animal); interface IRunnable<in T> { T TypeIns { set; } void CanRun(T t); }
既然与协变相反,那么它就代表着“输入”,抗变类型就只能用于方法的参数和属性的set。在FCL里抗变的接口和委托如下
IComparer<in T> IEqualityComparer<in T> IComparable<in T> System.Action<in T> System.Func<Out Tresult> Predicate<in T> Comparison<in T> Converter<in TInput,out TOutput>
可是变体不适用于上面的List<T>,因为这个泛型类在声明的时候并没有用上out关键字,就算是用上了也不现实,因为对于List<T>这个这个泛型类来说,它本身就存在着输入与输出两种行为,Add,Remove等方法就要利用到参数的输入,同时它本身又能通过索引器来获取某个所以值下的元素,既有out又有in的泛型相互矛盾,定义不出来。
本文因看见某位园有写了一篇相同主题的文章而写的,想着不久前某位同事也叫我探讨过变体,当时我看了不久就忘了,这回看到那位园友的博文,我想想我还是也记录一下吧!不放博客园首页了。
原文:http://www.cnblogs.com/HopeGi/p/3536587.html