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类型参数中协变.逆变.类型上界和类型下界的使用方法和 ...
随机推荐
- [译+改]最长回文子串(Longest Palindromic Substring) Part II
[译+改]最长回文子串(Longest Palindromic Substring) Part II 原文链接在http://leetcode.com/2011/11/longest-palindro ...
- 据说每个大牛、小牛都应该有自己的库——Event处理
今天抽时间写了一部分Event处理方面的函数愈发的觉得jQuery的优秀,自己前期的想法太粗糙,造成后面这些函数参数很多,操作很很不直观,看样子是要重构的节奏,还好小伙儿伴们安慰,架构都是改出来的.继 ...
- ios CGRect
/* rect(x,y,width,height); width, height正负代表了从原点的绘制方向,矩形的长宽都是取得绝对值 */ // Do a ...
- iOS----Xcode6或者Xcode7设置LaunchImage图标
最近设置LaunchImage图标时发现怎么都没有效果,后来发现是Xcode6中新建项目的时候会默认添加一个LaunchScreen.xib的文件,我们启动程序的时候也会发现,加载的时LaunchSc ...
- app的同源和域的问题
app的同源和域的问题
- mongodb-$type、limit、skip、sort方法、索引、聚合
一.$type操作符 $type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果. MongoDB 中可以使用的类型如下表所示: 类型 数字 备注 Double 1 String 2 ...
- CSS三列布局
× 目录 两侧定宽中间自适应 两列定宽一侧自适应 中间定宽两侧自适应一侧定宽两列自适应三列自适应总结 前面的话 前面已经介绍过单列定宽单列自适应和两列自适应的两列布局.本文介绍三列布局,分为两侧定宽中 ...
- java中并不是任意多个接口都可以实现多实现
interface A{ public abstract void show(); } interface B{ public abstract int show(); } public class ...
- java接口的应用举例
/* 接口的理解: 接口就是前期定义一个规则!某一个类A,为了扩展自身的功能,对外提供这个接口,后期只要是符合这个接口(规则) 的类(这个类是接口的子类),将子类对象的引用传递给类A中方法(方法中的参 ...
- 云计算之路-阿里云上:消灭“黑色n秒”第三招——禁用网卡的TCP/IP Offload
程咬金有三板斧,我们有三招.在这篇博文中我们要出第三招,同时也意味着昨天在“希望的田野”上的第二招失败了. 前两招打头(CPU)不凑效,这一招要换一个部位,但依然要坚持攻击敌人最弱(最忙最累)部位的原 ...