泛型在.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. Java多线程系列--“JUC锁”07之 LockSupport

    概述 本章介绍JUC(java.util.concurrent)包中的LockSupport.内容包括:LockSupport介绍LockSupport函数列表LockSupport参考代码(基于JD ...

  2. 【译】Activitys, Threads和 内存泄露

    Android编程中一个共同的困难就是协调Activity的生命周期和长时间运行的任务(task),并且要避免可能的内存泄露.思考下面Activity的代码,在它启动的时候开启一个线程并循环执行任务. ...

  3. AlwaysON 故障处理之辅助副本磁盘空间不足

    用户反馈AlwaysON辅助副本数据库查询的结果与主库不一致, 远程到服务器后发现数据库的状态显示为“未同步/可疑”, 查看数据库的日志,定位到出现错误的时间点,可以看到提示日志文件所在磁盘的“磁盘空 ...

  4. C#Light 再推荐,顺便介绍WP8 功能展示项目

    由于在项目中验证了C#Light脚本,C#Light的健壮和稳定程度已经得到了很大的提升. 现在可以更好的把C#Light介绍给大家使用,同时也有更多的自信,告诉大家这是一个已经具有商业价值的类库. ...

  5. Vue API阅读的小细节

    #后面是表达式,下面是参数列表,参数列表每行说明一个参数.每行的参数说明,最后边对应表达式的参数,左边是该参数的类型一类的说明.

  6. redis常用命令、常见错误、配置技巧等分享

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/117.html?1455860236 1. redis查看当前所有的key ...

  7. HTML学习入门

    HTML(元素.属性) HTML: 超文本标记语言   1. 超文本即为带有链接属性的文本  2.标记即为标签 一.body属性: bgcolor:页面背景颜色 text:文字颜色 backgroun ...

  8. [Linux]Linux下redis的安装及配置.

    在上一篇[Linux] linux下安装配置 zookeeper/redis/solr/tomcat/IK分词器 详细实例. 我们已经将redis所需tar包拷贝到了linux下的root 根目录下, ...

  9. Atitit 编程语言常用算法attilax总结

    Atitit 编程语言常用算法attilax总结 1. 编译算法分类and   数据操作算法.1 1.1. Tab driver stat  状态转换表格算法1 1.2. Nest case 词法分析 ...

  10. js显示yyyy年mm日dd天 星期几 的格式日期

    js代码: <script type="text/javascript"> var today = new Date(); var week; //存储星期几 var ...