C#编程总结(十四)dynamic
介绍
Visual C# 2010 引入了一个新类型 dynamic。 该类型是一种静态类型,但类型为 dynamic 的对象会跳过静态类型检查。 大多数情况下,该对象就像具有类型 object 一样。 在编译时,将假定类型化为 dynamic 的元素支持任何操作。 因此,您不必考虑对象是从 COM API、从动态语言(例如 IronPython)、从 HTML 文档对象模型 (DOM)、从反射还是从程序中的其他位置获取自己的值。 但是,如果代码无效,则在运行时会捕获到错误。
var与dynamic对比
1、var编译时替换为实际类型,而dynamic实际是object类型。
一旦被编译,编译期会自动匹配var 变量的实际类型,并用实际类型来替换该变量的申明,这看上去就好像我们在编码的时候是用实际类型进行申明的。而dynamic被编译后,实际是一个object类型,只不过编译器会对dynamic类型进行特殊处理,让它在编译期间不进行任何的类型检查,而是将类型检查放到了运行期。
2、智能感知。
以var声明的变量,支持“智能感知”,因为visual studion能推断出var类型的实际类型,而以dynamic声明的变量却不支持“智能感知”,因为编译器对其运行期的类型一无所知。对dynamic变量使用“智能感知”,会提示“此操作将在运行时解析”。
简单案例
编写一个hello world的测试程序,定义DynamicTest类型,并增加Welcome方法,其参数为name.
然后创建dynamic对象,调用Welcome方法。参数为空。
using System;namespace DynamicSample{ class Program { static void Main(string[] args) { dynamic obj = new DynamicTest(); obj.Welcome(); } } class DynamicTest { public void Welcome(string name) { Console.WriteLine("Hello {0},welcome to dynamic world.",name); } }}
看看发生什么事情呢,通过测试发现:
编译通过,没有任何异常。
运行时抛出异常,异常信息:
未处理Microsoft.CSharp.RuntimeBinder.RuntimeBinderException HResult=-2146233088 Message=“Welcome”方法没有采用“0”个参数的重载 Source=Anonymously Hosted DynamicMethods Assembly StackTrace: 在 CallSite.Target(Closure , CallSite , Object ) 在 System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid1[T0](CallSite site, T0 arg0) 在 DynamicSample.Program.Main(String[] args) 位置 E:\Donet\C#\DynamicSample\DynamicSample\Program.cs:行号 13 在 System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 在 System.Threading.ThreadHelper.ThreadStart() InnerException:
修正后:
class Program { static void Main(string[] args) { dynamic obj = new DynamicTest(); string name = "Tom"; obj.Welcome(name); Console.WriteLine("Input any key to exit."); Console.ReadKey(); } }
运行结果:
如果改为var,定义该对象,并调用方法,代码如下,编译器会报错:
var v1 = new DynamicTest(); v1.Welcome();
错误信息:
错误 CS7036 未提供与“DynamicTest.Welcome(string)”的必需形参“name”对应的实参 DynamicSample Program.cs 15 错误 CS7036 There is no argument given that corresponds to the required formal parameter 'name' of 'DynamicTest.Welcome(string)' DynamicSample
dynamic应用范围
1、在声明中,作为属性、字段、索引器、参数、返回值或类型约束的类型,都可以使用dynamic。
2、在显式类型转换中,作为转换的目标类型。任何对象都可以隐式转为dynamic。
3、在以类型充当值(如 is 运算符或 as 运算符右侧)或者作为 typeof 的参数成为构造类型的一部分的任何上下文中。
通过一个实例来具体说明:
class DynamicUser { ////// 字段 /// public dynamic userid; ////// 属性 /// public dynamic UserName { get; set; } ////// 玩游戏 /// (dynamic可以作为参数、返回值等) /// /// ///public dynamic Play(dynamic game) { dynamic defaultGame = "Play Basketball."; dynamic secGame = "Play with mud."; if (game is int) { return defaultGame; } else { return secGame; } } /// /// 显式类型转换 /// public void ConvertToDynamic(object obj) { dynamic d; d = (dynamic)obj; Console.WriteLine(d); } ////// 类型判定 /// (dynamic 可以使用is、as、typeof) /// public void TypeCheck() { int age = 20; Console.WriteLine("Age is Dynamic? {0}",age is dynamic); dynamic d = age as dynamic; Console.WriteLine("Age:{0}",d); Console.WriteLine("List's type is {0}",typeof(List )); } }
测试用例:
DynamicUser user = new DynamicUser(); user.userid = 123; user.UserName = "Lucy"; user.ConvertToDynamic(user.userid); user.ConvertToDynamic(user.UserName); user.TypeCheck(); Console.WriteLine("Input any key to exit."); Console.ReadKey();
测试结果:
dynamic的执行效率
关于dynamic的效率问题,这里暂不展开,后续专门来讨论...
应用
1、自动反射
2、COM组件互操作
3、混合编程,例如IronRuby和IronPython
4、处理Html DOM对象
5、还有一种应用,数据传输中格式转换,如:对象转json等,很方便