C#中协变与抗变(逆变)
泛型在.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#中协变与抗变(逆变)的更多相关文章
- C#中的协变(Covariance)和逆变(Contravariance)
摘要 ● 协变和逆变的定义是什么?给我们带来了什么便利?如何应用? ● 对于可变的泛型接口,为什么要区分成协变的和逆变的两种?只要一种不是更方便吗? ● 为什么还有不可变的泛型接口,为什么有的泛型接口 ...
- C#中的协变OUT和逆变
泛型接口和泛型委托中经常使用可变性 in 逆变,out 协变 从 list<string>转到list<object> 称为协变 (string 从object 派生,那么 ...
- 协变(covariant)和逆变(contravariant)
我们知道子类转换到父类,在C#中是能够隐式转换的.这种子类到父类的转换就是协变. 而另外一种类似于父类转向子类的变换,可以简单的理解为“逆变”. 上面对逆变的简单理解有些牵强,因为协变和逆变只能针对接 ...
- C# 协变out 、逆变 in
需求:泛型使用多态性 备注:协变逆变只能修饰 接口和委托 简单理解: 1.使用 in 修饰后为逆变,只能用作形参使用 ,参考 public delegate void Action<in T&g ...
- Java中的逆变与协变
看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...
- .NET 4.0中的泛型的协变和逆变
转自:http://www.cnblogs.com/jingzhongliumei/archive/2012/07/02/2573149.html 先做点准备工作,定义两个类:Animal类和其子类D ...
- 转载.NET 4.0中的泛型的协变和逆变
先做点准备工作,定义两个类:Animal类和其子类Dog类,一个泛型接口IMyInterface<T>, 他们的定义如下: public class Animal { } public ...
- scala学习笔记-类型参数中协变(+)、逆变(-)、类型上界(<:)和类型下界(>:)的使用
转载自 fineqtbull http://fineqtbull.iteye.com/blog/477994 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的 ...
- Scala类型参数中协变(+)、逆变(-)、类型上界(<:)和类型下界(>:)的使用
转自:http://fineqtbull.iteye.com/blog/477994#bc2364938 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的使用方法和 ...
随机推荐
- FusionCharts简单教程(五)-----FusionCharts中的那些特殊符号
在FusionCharts中有些特殊字符,我们需要进行编码操作才能够使用,否则就无法正常显示. 欧元符号 在FusionCharts里显示"€",你需要用 ...
- OpenJDK将对Android开发产生怎样的影响?
转载于:http://www.itxuexiwang.com/a/liunxjishu/2016/0228/182.html?1456926201 Google已决定将从下一版本的Android开始采 ...
- Node.js入门:前后端模块的异同
通常有一些模块可以同时适用于前后端,但是在浏览器端通过script标签的载入JavaScript文件的方式与Node.js不同.Node.js在载入到最终的执行中,进行了包装,使得每个文件中的 ...
- fir.im Weekly - 600个 Android 开源项目汇总
本期 Weekly 收集了一些热度资源,包含 Android.iOS 开发工具与源码分享,程序员也应该了解的产品运营.设计等 Tips ,希望对你有帮助. 600个Android开源项目汇总 勤劳的 ...
- iOS 8.1.3 “各路助手挺尸”、“封杀一切助手
图片来自 http://www.redmondpie.com 最近苹果发布了8.1.3系统更新.从更新日志看,没有多少变化(错误修复,提高稳定性和性能),但是苹果修复了一个"漏洞" ...
- IOS-各控件默认尺寸和参考图标大小
UITabBar
- KnockoutJS 3.X API 第五章 高级应用(5) 使用预处理扩展Knockout绑定语法
注意:这是一种高级技术,通常仅在创建可重用绑定或扩展语法的库时使用. 这不是你通常需要做的时候使用Knockout构建应用程序. 从Knockout 3.0开始,开发人员可以通过提供在绑定过程中重写D ...
- javascript中function 函数递归的陷阱问题
//看下这个递归方法,最后输出的值function fn(i){ i++; if(i<10){ fn(i); } else{ return i; } } var result = fn(0); ...
- css margin
css中margin边界叠加问题: 看个同方向和异方向margin重叠现象: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transiti ...
- MYSQL的深入学习--优化步骤
MySql优化的一般步骤 1.通过show status 命令了解各种sql的执行效率 SHOW STATUS提供msyql服务器的状态信息 一般情况下,我们只需要了解以”Com”开头的指令 show ...