Visual Studio 2010 已经离我们越来越近,关于 C# 4.0 的 Break Changes 也已经全部成型。在 C# 4.0 发布时,我们将能够看到如下的新特性:
-
1、动态查找
-
2、命名参数
-
3、可选参数和默认值
-
4、Covariance 和 Contra-variance
-
5、其他 .NET Framework 4.0 的更新 (DLR, No-PIA 等)
今天我们给大家介绍一下 C# 4.0 中的动态查找。
一个简单的例子
下面的代码动态的获取一个 COM 对象类型,并通过该类型创建这个 COM 对象的实例,并准备调用该实例上的一个方法实现我们需要的功能。这个例子引用了 Speech API 中的 SAPI.SpVoice 对象,并调用了其 Speak() 方法。
1: using System;
2:3: Type type = Type.GetTypeFromProgID("SAPI.SpVoice");
4: dynamic spVoice = Activator.CreateInstance(type);
5: spVoice.Speak("Hello, C# 4.0!");
编译并运行此示例,我们通过计算机的音箱得到了正确的语音。
现在我们开始思考一个问题,spVoice.Speak(string) 这个函数签名其实在设计时以及编译时对于 C# 编译器来说都是未知的。因为 spVoice 变量的类型是 System.__ComObject,并且由于 SAPI.SpVoice 对应的 ProgID 指向一个非托管的 COM 对象,加上我们并没有导入任何 TLB 库,因此,Speak() 方法只能是在运行时由编译器自动绑定。
这就是动态查找最基本的意图,它的提出是为了在 Office 以及 COM 互操作性编程中更加简化代码。dynamic 变量的所有运行时类型信息都直接由运行时上下文绑定并执行(称之为“晚期绑定”),这些工作通过 System.Dynamic.RuntimeBinding 类完成。
注意:dynamic 不同于 object。object 是任何类的基础类,它是一个强类型的 CLR 类型,是引用类型。它具备完整的运行时信息,任何企图访问 object 不存在的方法签名或者属性都会被编译时由编译器检查出来并报告错误。dynamic 类型在编译时可能是未知的,所有针对它类型上的调用在编译时是不会报告错误的,只有在运行时由 DLR 去检查这些信息后,才能确定一个调用是否成功或者失败。
由于 dynamic 的这些特性,使得它广泛用于 COM 以及其他互操作编程中,它为我们的代码带来了简化和便利,但同时由于这个口子已经被打开,所有强类型都可以被转化为 dynamic,所以它如果被滥用,则会对代码的维护难度有很大的提高。因为编译器这个时候并不能在编译时检查更多的错误了。所以我们强烈建议您除了在互操作方面应用 dynamic 外,不要在其他地方滥用,以免对现有代码产生潜在的维护成本。
dynamic 和 CLR 类型的转换
理论上,任何 CLR 支持的类型都可以转化为 dynamic。dynamic 实现了 implicit 和 explicit 转换运算符,因此,下面的语句都是合法的。
1: int? i = 2;
2: string s = string.Empty;3: object o = null;4: dynamic d1 = i;5: dynamic d2 = s;6: var d3 = o as dynamic;
dynamic 的使用范围
由于 dynamic 它本身就是一个类型,因此可以应用在任何需要类型的地方。这些地方包括:
- 1、变量声明;
- 2、函数、委托、Lambda 表达式的参数类型,或者具备泛型的类型参数;
- 3、TypeOf 运算;
- 4、类型转换以及 is, as 运算。
结论
C# 4.0 中的动态查找为我们实现 COM 和 Office 互操作提供了更好的解决方案,这也使得 C# 更加靠近 DLR,但如何确定在哪些地方应该使用 dynamic 却很难让我们抉择,跟当年 var 一样,dynamic 的提出总会有好的一面和坏的一面,重要的是您是如何处理它的。