VS2010开发体验系列之二 - 语言C#4.0
2010-05-06 15:28
369 查看
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。
![](http://hi.csdn.net/attachment/201004/29/1670386_12725478170pjf.png)
刚才讲到, 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在语言层面的新特性, 当然, 还有很多细节, 光协变和逆变就可以写出一本书, 留待以后研究.
DLR(动态语言运行时)
命名参数和可选参数
特定于COM的互操作
协变和逆变
笔者首次尝试了这4个新特性,下面一一做简单的介绍:
1. DLR(动态语言运行时)
在CLR之上,.NET引入了一个叫DLR(Dynamic Language Runtime)的组件,这套组件提供了一系列的服务,用以支持动态语言。细分下来,主要是两方面:在静态语言类型中引入动态类型和支持动态语言比如IronRuby&IronPython. 以下这个架构图可以帮助您理解DLR。
![](http://hi.csdn.net/attachment/201004/29/1670386_12725478170pjf.png)
刚才讲到, DLR提供了两个方面的支持,下面分别演示一下代码:
第一个方面,静态语言类型的动态支持,让我们看看一组代码,假设有三个类,Customer, VIP, Parterner.
public class Customer { public String Name { get; set; } } public class VIP : Customer { public String CustomerManager { get; set; } } public class Parterner { public String Name { get; set; } public String Speciality { get; set; } }
dynamic test = new VIP(); test.Name = "test"; // Compile Pass, Runtime Pass. test.CustomerManager = "mgt"; // Compile Pass, Runtime Pass. test.Speciality = ""; // Compile Pass, Runtime Error.(No such Property "Speciality" for VIP.) test = new Customer(); test.Name = "test"; // Compile Pass, Runtime Pass. test.CustomerManager = "mgt"; // Compile Pass, Runtime Error.(No such Property "CustomerManager" for Customer.) test.Speciality = ""; // Compile Pass, Runtime Error.(No such Property "Speciality" for Customer.) test = new Parterner(); test.Name = "test"; // Compile Pass, Runtime Pass. test.CustomerManager = "mgt"; // Compile Pass, Runtime Error.(No such Property "CustomerManager" for Parterner.) test.Speciality = ""; // Compile Pass, Runtime Pass.
可以看到,对于dynamic关键字声明的对象,是不会在编译时检查类型的成员比如属性的,在runtime时DLR会动态检查对象的成员,并执行之。
有人认为,这样做的好处是,可以在修改了类名的情况下,保持调用者代码不变。我个人认为这个功能意义不大,如果非要保持调用者不变,做好interface就行了,何必这么辛苦呢。更何况,这种静态类型跟动态类型之间的转换,performance还是比较差的,尽管DLR提供了方法调用的cache功能,性能上能有多大提升,还需验证。
第二个方面,是对动态语言的支持。
一个是对IronPython和IronRuby的支持,一个是C#/VB等静态类型语言与动态类型语言的交互。前者超出了C#4.0的范畴,我们重点看看后者。
class MyDynamicObject : DynamicObject { Dictionary<String, object> items = new Dictionary<String, object>(); public String Name { get; set; } public override bool TryGetMember(GetMemberBinder binder, out object result) { return items.TryGetValue(binder.Name, out result); } public override bool TrySetMember(SetMemberBinder binder, object value) { items[binder.Name] = value; return true; } }
如以上代码所示,这个动态类型的核心是TryGetMember和TrySetMember这两个方法(当然,必须继承DynamicObject类,或者DynamiceMetaObject类,或者实现IDynamicMetaObjectProvider接口). 当编译器发现代码试图get/set一个没有预先定义的Property时,就会让DLR去TryGetMember/TrySetMember方法中寻找对应的Property。这个实现也是与动态语言比如IronPython/IronRuby交互的基础。
2. 命名参数和可选参数
这个比较简单,相信下面的代码可以很快让人明白这个特性。
可选参数示例(顾名思义,就是定义过默认值的参数,是可选的,调用方可以决定是否传值进来)
public void Process( string data, bool ignoreWS = false, ArrayList moreData = null ) { // Actual work done here } ArrayList myArrayList = new ArrayList(); Process( "foo" ); // valid Process( "foo", true ); // valid Process( "foo", false, myArrayList ); // valid Process( "foo", myArrayList ); // invalid. 注意这里,下面的命名参数可以解决这个问题。
命名参数示例(对于上面最后一种情况,可以在调用方显示制定传入值属于哪个参数)
ArrayList myArrayList = new ArrayList(); Process( "foo", moreData: myArrayList); // valid, ignoreWS omitted
3. 特定于COM的互操作
还记得这样的代码么, 当我们想访问一个Excel文件, 我们需要写一堆无用的ref missing, 如下:
Excel.Application app = new Excel.ApplicationClass(); Excel.Workbook book= app.Workbooks._Open(@"Sample.xls", Missing.Value,Missing.Value,Missing.Value,Missing.Value ,Missing.Value,Missing.Value,Missing.Value,Missing.Value ,Missing.Value,Missing.Value,Missing.Value,Missing.Value);
现在, 简化成下面这样了,
Excel.Application app = new Excel.ApplicationClass(); Excel.Workbook book= app.Workbooks._Open(@"Sample.xls");
对此, 没什么好说的, 只能说原来太失败了.
据介绍, 在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做的, 看如下代码:
public class Animal { } public class Cat : Animal { } public delegate Animal AniHandler(Animal a); public static Animal AniMethod(Animal a) { return null; } public static Cat CatMethod(Object o) { return null; } public static void TestCovariance() { AniHandler handler1 = AniMethod; AniHandler handler2 = CatMethod; // CatMethod返回值, 做了协变, CatMehod的返回 // 值Cat, 变到了AniHandler的返回值Animal; // CatMethod的参数, 做了逆变, CatMethod的参 // 数Object, 变到了AniHandler的参数Animal. }
在C#4.0中, 增加了对泛型的支持, 包括delegate的泛型参数和泛型的interface. 还是拿delegate举例,
协变, 如下代码在C#4.0以前,是不合法的:
delegate T THandler<T>(); static void Main(string[] args) { THandler<Cat> catHandler= () => new Cat(); THandler<Animal> aniHandler = catHandler; //这段代码会报错. }
在C#4.0里面, 因为有了对泛型委托协变的支持, 可以稍作修改如下:
delegate T THandler<out T>(); //此处声明为协变变量 static void Main(string[] args) { THandler<Cat> catHandler= () => new Cat(); THandler<Animal> aniHandler = catHandler; //这段代码就不会报错了. }
逆变, 如下代码在C#4.0以前, 是不合法的:
delegate void THandler<T>(T t); public static void TestContravariance() { THandler<Animal> aniHandler = (ani) => { }; THandler<Cat> catHandler = aniHandler; //这段代码会报错. }
在C#4.0里面, 因为有了对泛型委托逆变的支持, 可以稍作修改如下:
delegate void THandler<in T>(T t); public static void TestContravariance() { THandler<Animal> aniHandler = (ani) => { }; THandler<Cat> catHandler = aniHandler; //这段代码就不会报错了. }
同理, 对于泛型interface, 也是如此.
关于协变和逆变, 借鉴了这篇帖子http://www.cnblogs.com/fox23/archive/2010/03/09/1615698.html, 可以去这篇帖子里看更详细的说明.
以上是C#4.0在语言层面的新特性, 当然, 还有很多细节, 光协变和逆变就可以写出一本书, 留待以后研究.
相关文章推荐
- [MSDN]C# 3.0 锐利体验系列课程 之一 语言基础扩充
- 用c#开发安卓程序 (xamarin.android)系列之二 简单的聊天程序
- VS2010开发体验系列之一 - 新特性概述
- C# 4.0开发体验——方法参数默认值
- vs2010自带C# 4.0 示例_语言示例_第一部分
- C#2.0 锐利体验系列课程(4):杂项技术,以及C#语言的未来发展 (Level 300)
- C# 开发 OPC Server 系列之二
- [MSDN]C# 3.0 锐利体验系列课程 之二 Lambda表达式
- 用c#开发安卓程序 (xamarin.android)系列之二 简单的聊天程序
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十六)飞行模式 – 自由VS天空
- Windows 7程序开发系列之二(JumpList篇1 - User Task)
- java web 轻量级开发全体验之二:安装与配置环境
- 基于C#语言开发的IM系统--数据库结构图(通讯框架为networkcomms2.3.1)【即将开源】
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十七)远距离单体攻击与单体魔法
- C# 海康DVR客户端开发系列(2)—— 封装API (3)
- (转)C#多国语言支持的WinForm程序开发
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十八) 落雷!治疗!陷阱!连锁闪电!多段群伤!魔法之终极五重奏①
- ASP.NET开发实践系列课程之c#代码优化
- 更改VS2010的[默认开发语言]
- C#基础系列之第一弹:语言规范