C# 新特性_协变与逆变 (.net 4.0)
C#4.0中有一个新特性:协变与逆变。可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的。
协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变。什么?泛型的参数还能声明?对,如果有了参数的声明,则该泛型接口或者委托称为“变体”。
List<汽车> 一群汽车 = new List<汽车>();
List<车子> 一群车子 = 一群汽车;
显然,上面那段代码是会报错的, 虽然汽车继承于车子,可以隐士转换为车子,但是List<汽车>并不继承于List<车子>,所以上面的转换,是行不通的。
IEnumerable<汽车> 一群汽车 = new List<汽车>();
IEnumerable<车子> 一群车子 = 一群汽车;
然而这样却是可以的。那么IEnumerable接口有什么不同呢,我们且看编译器的提示:

我们可以看到,泛型参数的,用了一个“out”关键字作为声明。看来,关键是这个在起作用了。
“协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型。
“逆变”则是指能够使用派生程度更小的类型。逆变,逆于常规的变。
协变和逆变,使用“out”,和“in”两个关键字。但是只能用在接口和委托上面,对泛型的类型进行声明
当声明为“out”时,代表它是用来返回的,只能作为结果返回,中途不能更改。
当声明为"in"时,代表它是用来输入的,只能作为参数输入,不能被返回。
回到上面的例子,正因为“IEnumerable”接口声明了out,所以,代表参数T只能被返回,中途不会被修改,所以,IEnumerable<车子> 一群车子 = 一群汽车; 这样的强制转换
是合法的,IL中实际上是作了强制转换的。
IEnumerable是NET中自带的,其余还有如下接口和委托:

接口:
IQueryable<out T>
IEnumerator<out T>
IGrouping<out TKey,out TElement>
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>

此外,我们自己定义泛型接口的时候也可以使用协变和逆变,我们不妨来看一个示例,来体现协变的特征
interface 接口<out T>
{
T 属性 { get; set; }
}
我定义一个接口,一个具有get和set访问器的属性,然而,编译是报错的,提示:变体无效: 类型参数“T”必须为对于“test.接口<T>.属性”有效的 固定式。“T”为 协变。
正因为我声明了T为协变,所以,T只能被返回,不允许被修改,所以,如果去掉“set”访问器,才可以编译通过。
同样,如果我在“接口”中声明一个方法
void 方法(T t);
同样是会报错的,T被声明了协变,“方法(T t)”的存在就不可取。

class Program
{
static void Main(string[] args)
{
接口<汽车> 一群汽车 = new 类<汽车>();
接口<车子> 一群车子 = 一群汽车;
}
}
interface 接口<out T>
{
T 属性
{
get;
}
}
class 类<T> : 接口<T>
{
public T 属性
{
get { return default(T); }
}
}

上面的代码是可以编译通过的,因为泛型接口“接口”声明了协变,所以“接口<车子> 一群车子 = 一群汽车;”是可以强制转换成功的,看吧,我们自己声明的同样可以实现目的。
如果我把以上的代码,把“out”改成“in”呢? 显然不行,因为声明“in”规定了T不能被返回,编译无法通过的。
然而下面的代码是正确的:

interface 接口<in T>
{
void 方法(T t);
}
class 类<T> : 接口<T>
{
public void 方法(T t)
{ }
}

声明“in”不允许被返回,但是可以进行更改。
接着看:

static void Main(string[] args)
{
接口<车子> 一群车子 = new 类<车子>();
接口<汽车> 一群汽车 = 一群车子;
}

啊,这怎么也可以啊,“车子”是父类,“汽车”是子类,汽车转换为车子正常,车子转换为汽车,这样也行?
其实“车子”也好,“汽车”也好,在这里都只是泛型参数,并不是他们俩之间的转换,这个基础的概念必须明白,别绕进去了。
这就是逆变。因为“接口”声明了“in”关键字,声明为逆变,让参数去接受一个相对更“弱“的类型,其实是让一个参数的类型,更加具体化,更明确化的一个过程。
C# 新特性_协变与逆变 (.net 4.0)的更多相关文章
- c#4.0新特性之协变与逆变
1.C#3.0以前的协变与逆变 如果你是第一次听说这个两个词,别担心,他们其实很常见.C#4.0中的协变与逆变[1](Covariance and contravariance)有了进一步的完善,主要 ...
- C#4.0泛型的协变,逆变深入剖析
C#4.0中有一个新特性:协变与逆变.可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的. 协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变.什么 ...
- .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 ...
- C#协变和逆变
我们知道在C#中,是可以将派生类的实例赋值给基类对象的.
- 再谈对协变和逆变的理解(Updated)
去年写过一篇博客谈了下我自己对协变和逆变的理解,现在回头看发现当时还是太过“肤浅”,根本没理解.不久前还写过一篇“黑”Java泛型的博客,猛一回头又是“肤浅”,今天学习Java泛型的时候又看到了协变和 ...
- scala学习笔记-类型参数中协变(+)、逆变(-)、类型上界(<:)和类型下界(>:)的使用
转载自 fineqtbull http://fineqtbull.iteye.com/blog/477994 有位je上的同学来短信向我问起了Scala类型参数中协变.逆变.类型上界和类型下界的 ...
- .NET可变性解析(协变和逆变)
[一]何为可变性 可变性是.NET4.0中的一个新特性,可变性可分为 : 协变性.逆变性.不可变性. 那么在.NET4.0之前是否有可变性? 答案是肯定的,我们可以通过下面的几个实例来简单的了解一下. ...
- 在net中json序列化与反序列化 面向对象六大原则 (第一篇) 一步一步带你了解linq to Object 10分钟浅谈泛型协变与逆变
在net中json序列化与反序列化 准备好饮料,我们一起来玩玩JSON,什么是Json:一种数据表示形式,JSON:JavaScript Object Notation对象表示法 Json语法规则 ...
随机推荐
- iostat 离线安装
由于lucene需要一定的io读写顾安装iostat来对磁盘io进行监控 iostat 属于sysstat下的功能 git路径如下:https://github.com/sysstat/sysstat ...
- C#开发者准备的通用性代码审查清单
这是为C#开发者准备的通用性代码审查清单,可以当做开发过程中的参考.这是为了确保在编码过程中,大部分通用编码指导原则都能注意到.对于新手和缺乏经验(0到3年工作经验)的开发者,参考这份清单编码会很帮助 ...
- 做一个有理想的IT人
前段时间一直以来都在思考生命的价值的问题,一直在想人的一生的追求是什么.在这个物欲横流的社会,对人的价值的定义只是在财富积累的多少,这个是大多数人所认为的.但人的一生顶多百年,百年之后这些虚荣划归为尘 ...
- Windows通用应用平台
什么是 UWP? 很多程序员都有一个梦想:希望自己开发的软件能够轻而易举的在所有平台上运行,而不是把同样的需求,用不同的技术.工具重新开发才能够运行在所有平台上.这就是跨平台,很多软件从业者都在为这个 ...
- [转]Google2012.9.24校园招聘会笔试题
代码: [cpp] view plaincopy //转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/8017703 boo ...
- jquery.validate详解二
五.常用方法及注意问题 1.用其他方式替代默认的SUBMIT $().ready(function() { $("#signupForm").validate({ ...
- ASP.net ListItem Attributes 属性回传丢失的解决方案
该方法为网上整理 1. 新继承一个列表控件 新控件中重写两个方法: using System; using System.Collections.Generic; using System.Linq; ...
- VB中DateDiff 函数解释
VB中DateDiff 函数使用方法 DateDiff (interval, Date1 , Date2[,firstweekofyear[,firstweekofyear]]) 返回一个Varia ...
- LabVIEW新手5大错误
虽然NI LabVIEW软件长期以来一直帮助工程师和科学家们快速开发功能测量和控制应用,但不是所有的新用户都会遵循LabVIEW编程的最佳方法. LabVIEW图形化编程比较独特,因为只需看一眼用户的 ...
- 关于Http协议(2)--转载
原文链接:http://www.cnblogs.com/mcad/ HTTP工作原理图 请求报文 1.请求报文长什么样? Chrome核心的请求报文 2.报文结构 3.报文头部每个字段的意义 //从 ...