首页 > 其他 > 详细

C#中协变与抗变(逆变)

时间:2014-01-31 13:09:08      阅读:357      评论:0      收藏:0      [点我收藏+]

  泛型在.NET 2.0中正式的引入。在使用泛型的过程中,联系上面向对象的继承性。往往很容易想当然敲出类似以下代码

List<Animal> animalLst=new List<Dog>;

显然这样编译是不通过的。虽然Dog和Animal之间有继承性,但是List<Animal>和List<Dog>这两个类之间并没有继承性。如果要解决这样的问题,用上协变与抗变(逆变),它们统称为变体。是.NET 4.0引入的新特性,但是早在.NET 2.0就引入了。

  变体适用于泛型接口与泛型委托,在我们声明泛型借口或泛型委托时,加上out或in关键字就能实现。

  • out是用于协变,这就好比子类通过隐式转换成基类的情形,这么平淡的转换,与“协”的感觉类似;
  • in是用于抗变,类似于基类强制转换成子类,带有一些负面的感觉的,于是“逆”或者“抗”关联上了。

两者可以说得上是用于整条类的继承链上转换工作的,但是方向不同。

那么先来看看协变

bubuko.com,布布扣
    delegate T AnimalAction1<out T>();

    interface IProduce<out T>
    {
        T TypeIns { get; }

        T CreteNewTypeIns();
    }
bubuko.com,布布扣

  out这个关键字使人联想到“输出”,既然是出的话,那么协变的类型只能用于方法的返回值或者是属性的get,如果变量作为方法的参数(即使是带out关键字的参数)和属性的set,那么编译会报错。那么在FCL里面是协变的接口和委托如下

bubuko.com,布布扣
IQueryable<out T>
IEnumerator<out T>
IGrouping<out TKey,out TElement>

Converter<in TInput,out TOutput>
bubuko.com,布布扣

看上去都是返回泛型T的。

再看看抗变

bubuko.com,布布扣
    delegate void AnimalBark<in T>(T animal);

    interface IRunnable<in T>
    {
        T TypeIns { set; }

        void CanRun(T t);
    }
bubuko.com,布布扣

 

既然与协变相反,那么它就代表着“输入”,抗变类型就只能用于方法的参数和属性的set。在FCL里抗变的接口和委托如下

bubuko.com,布布扣
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>
bubuko.com,布布扣

 

  可是变体不适用于上面的List<T>,因为这个泛型类在声明的时候并没有用上out关键字,就算是用上了也不现实,因为对于List<T>这个这个泛型类来说,它本身就存在着输入与输出两种行为,Add,Remove等方法就要利用到参数的输入,同时它本身又能通过索引器来获取某个所以值下的元素,既有out又有in的泛型相互矛盾,定义不出来。
  本文因看见某位园有写了一篇相同主题的文章而写的,想着不久前某位同事也叫我探讨过变体,当时我看了不久就忘了,这回看到那位园友的博文,我想想我还是也记录一下吧!不放博客园首页了。

C#中协变与抗变(逆变)

原文:http://www.cnblogs.com/HopeGi/p/3536587.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!