泛型在.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是用于抗变,类似于基类强制转换成子类,带有一些负面的感觉的,于是“逆”或者“抗”关联上了。

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

那么先来看看协变

    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的泛型相互矛盾,定义不出来。
  本文因看见某位园有写了一篇相同主题的文章而写的,想着不久前某位同事也叫我探讨过变体,当时我看了不久就忘了,这回看到那位园友的博文,我想想我还是也记录一下吧!不放博客园首页了。

C#中协变与抗变(逆变)的更多相关文章

  1. C#中的协变(Covariance)和逆变(Contravariance)

    摘要 ● 协变和逆变的定义是什么?给我们带来了什么便利?如何应用? ● 对于可变的泛型接口,为什么要区分成协变的和逆变的两种?只要一种不是更方便吗? ● 为什么还有不可变的泛型接口,为什么有的泛型接口 ...

  2. C#中的协变OUT和逆变

    泛型接口和泛型委托中经常使用可变性 in  逆变,out  协变 从 list<string>转到list<object> 称为协变 (string 从object 派生,那么 ...

  3. 协变(covariant)和逆变(contravariant)

    我们知道子类转换到父类,在C#中是能够隐式转换的.这种子类到父类的转换就是协变. 而另外一种类似于父类转向子类的变换,可以简单的理解为“逆变”. 上面对逆变的简单理解有些牵强,因为协变和逆变只能针对接 ...

  4. C# 协变out 、逆变 in

    需求:泛型使用多态性 备注:协变逆变只能修饰 接口和委托 简单理解: 1.使用 in 修饰后为逆变,只能用作形参使用 ,参考 public delegate void Action<in T&g ...

  5. Java中的逆变与协变

    看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...

  6. .NET 4.0中的泛型的协变和逆变

    转自:http://www.cnblogs.com/jingzhongliumei/archive/2012/07/02/2573149.html 先做点准备工作,定义两个类:Animal类和其子类D ...

  7. 转载.NET 4.0中的泛型的协变和逆变

    先做点准备工作,定义两个类:Animal类和其子类Dog类,一个泛型接口IMyInterface<T>, 他们的定义如下:   public class Animal { } public ...

  8. scala学习笔记-类型参数中协变(+)、逆变(-)、类型上界(<:)和类型下界(>:)的使用

    转载自  fineqtbull   http://fineqtbull.iteye.com/blog/477994 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的 ...

  9. Scala类型参数中协变(+)、逆变(-)、类型上界(<:)和类型下界(>:)的使用

    转自:http://fineqtbull.iteye.com/blog/477994#bc2364938 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的使用方法和 ...

随机推荐

  1. 2015继续任性——不会Git命令,照样玩转Git

    最近事情比较多,一眨眼,已经半个月没有写博客了~不得不感慨光阴似箭啊!当然,2015年有很多让我们期待的事情,比如win10正式版..NET开源.VS2015等等.想想都让人兴奋啊~~ 为了迎接VS2 ...

  2. C#Light Everywhere

    C#语法嵌入式脚本,0.1Beta版本咯,可用于各种环境,欢迎测试. 可以解决各种热更新问题 比如Unity在AOT环境下,比如各种不能采用动态加载DLL的场合. 如果遇到bug,请给我留言,我会从速 ...

  3. Perl重命名当前目录下的文件

    下载的zip包解压后,中文都变成了乱码,就写了个脚本重命名文件. use strict; use warnings; use Cwd; sub main { my $dir = getcwd(); o ...

  4. AWS助理架构师认证考经

    上周考了亚马逊的解决方案架构师-助理级别的认证考试并顺利通过.这也算是对自己AWS服务熟悉程度的一种检验.在准备考试的过程中,把自己学习到的AWS知识都梳理了一遍,也算是收获颇丰.这次特意分享了该认证 ...

  5. 让我欲罢不能的node.js

    从我大一接触第一门编程语言C开始,到现在工作三年陆续接触到了C.汇编.C++.C#.Java.JavaScript.PHP,还有一些HTML.CSS神马的,从来没有一门语言让我像对node.js一样的 ...

  6. Java-数组练习5

    5.从键盘上输入一个正整数n,请按照以下五行杨辉三角形的显示方式, 输出杨辉三角形的前n行.请采用循环控制语句来实现. (三角形腰上的数为1,其他位置的数为其上一行相邻两个数之和.) 1 1   1 ...

  7. 基础才是重中之重~AutoMapper为已有目标对象映射

    回到目录 AutoMapper各位一定不会陌生,大叔之前的文章中也提到过,曾经也写过扩展方法,以方便程序开发人员去使用它,而在最近,大叔在一个API项目里,在一个POST请求由DTO对象为实体对象赋值 ...

  8. linux命令 - alias

    linux命令 - alias 为自己的常用命令语句指定别名,快捷方式 $ alias /? Usage: alias [/reload] [/d] [name=full command] /relo ...

  9. Java多线程synchronized同步

    非线程安全问题 “非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程问题”.也即是说,方法中的变量永远是线程安全的. 如果多个线程共同访问1个对象中的实例变量,则可能线程 ...

  10. 学习WPF——使用Font-Awesome图标字体

    图标字体介绍 在介绍图标字体之前,不得不介绍图标格式ICON ICON是一种图标格式,我们操作系统中各种应用程序都包含一个图标 比如QQ程序的图标是一个可爱的企鹅,我的电脑是一个显示器图标 ----- ...