C#从1.0到4.0, 每次都会引入比较大的变化, 比如2.0的泛型,3.0的var,这次4.0也引入了一些新的东西,如下:
- DLR(动态语言运行时)
- 命名参数和可选参数
- 特定于COM的互操作
- 协变和逆变
笔者首次尝试了这4个新特性,下面一一做简单的介绍:
1. DLR(动态语言运行时)
在CLR之上,.NET引入了一个叫DLR(Dynamic Language Runtime)的组件,这套组件提供了一系列的服务,用以支持动态语言。细分下来,主要是两方面:在静态语言类型中引入动态类型和支持动态语言比如IronRuby&IronPython. 以下这个架构图可以帮助您理解DLR。
刚才讲到, DLR提供了两个方面的支持,下面分别演示一下代码:
第一个方面,静态语言类型的动态支持,让我们看看一组代码,假设有三个类,Customer, VIP, Parterner.
可以看到,对于dynamic关键字声明的对象,是不会在编译时检查类型的成员比如属性的,在runtime时DLR会动态检查对象的成员,并执行之。
有人认为,这样做的好处是,可以在修改了类名的情况下,保持调用者代码不变。我个人认为这个功能意义不大,如果非要保持调用者不变,做好interface就行了,何必这么辛苦呢。更何况,这种静态类型跟动态类型之间的转换,performance还是比较差的,尽管DLR提供了方法调用的cache功能,性能上能有多大提升,还需验证。
第二个方面,是对动态语言的支持。
一个是对IronPython和IronRuby的支持,一个是C#/VB等静态类型语言与动态类型语言的交互。前者超出了C#4.0的范畴,我们重点看看后者。
如以上代码所示,这个动态类型的核心是TryGetMember和TrySetMember这两个方法(当然,必须继承DynamicObject类,或者DynamiceMetaObject类,或者实现IDynamicMetaObjectProvider接口). 当编译器发现代码试图get/set一个没有预先定义的Property时,就会让DLR去TryGetMember/TrySetMember方法中寻找对应的Property。这个实现也是与动态语言比如IronPython/IronRuby交互的基础。
2. 命名参数和可选参数
这个比较简单,相信下面的代码可以很快让人明白这个特性。
可选参数示例(顾名思义,就是定义过默认值的参数,是可选的,调用方可以决定是否传值进来)
命名参数示例(对于上面最后一种情况,可以在调用方显示制定传入值属于哪个参数)
3. 特定于COM的互操作
还记得这样的代码么, 当我们想访问一个Excel文件, 我们需要写一堆无用的ref missing, 如下:
现在, 简化成下面这样了,
对此, 没什么好说的, 只能说原来太失败了.
据介绍, 在C#4.0中, 对COM的互操作主要做了一下改进,
Automatic object -> dynamic mapping
Optional and named parameters
Indexed properties
Optional “ref” modifier
Interop type embedding (“No PIA”)
有空可以仔细研究每个改进的细节.
4. 协变和逆变
这个feature更像是修bug。
我觉得需要先解释一下什么是协变, 什么是逆变.
所谓协变, 是指把类型从子类变到基类; 逆变, 则是把类型从基类变到子类. 在C#3.0中, 也有协变和逆变, 是针对delegate做的, 看如下代码:
在C#4.0中, 增加了对泛型的支持, 包括delegate的泛型参数和泛型的interface. 还是拿delegate举例,
协变, 如下代码在C#4.0以前,是不合法的:
在C#4.0里面, 因为有了对泛型委托协变的支持, 可以稍作修改如下:
逆变, 如下代码在C#4.0以前, 是不合法的:
在C#4.0里面, 因为有了对泛型委托逆变的支持, 可以稍作修改如下:
同理, 对于泛型interface, 也是如此.
关于协变和逆变, 借鉴了这篇帖子http://www.cnblogs.com/fox23/archive/2010/03/09/1615698.html, 可以去这篇帖子里看更详细的说明.
以上是C#4.0在语言层面的新特性, 当然, 还有很多细节, 光协变和逆变就可以写出一本书, 留待以后研究.