1 概述:
在早期的.NET Framework中,“Var”关键字和匿名方法开启了C#走向动态的道路,在4.0中,动态类型被添加进去。尽管C#是一个静态类型的语言,但这些额外的添加给C#带来了动态的能力。在这一章中,我们探讨一下动态类型以及它的一些使用规则,包括DynamicObject的实现和它的使用。
2 动态语言运行时(Dynamic Language Runtime):
C# 4.0中的动态是动态语言运行时(DLR)的一部分,DLR是被添加进CLR中的一系列服务,它允许添加额外的动态语言,比如Ruby 和Python, 而且还允许C#具有一些这些动态语言所拥有的功能。
在.NET Framework中,DLR位于System.Dynamic命名空间,其他一些相关的类位于System.Runtime.CompilerServices命名空间。
3 动态类型(The Dynamic Type):
动态类型允许你的代码绕过编译时的类型检查,编译器假设你为动态对象定义的一切操作都是合法的,如果定义的操作非法,错误也只会在运行时被侦测。
与var不同的是,一个对象如果被定义为Dynamic,它可以在运行时改变类型。需要记住的是,当var被使用,对象的目标类型会被延迟,一旦类型被确定,它将不能够改变。而动态类型不仅可以改变,而且还可以改变很多次,注意这和对象的类型转换是不同的。例如:int 不能够转换成Person类型,但是如果对象是dynamic的,就可以这样做。
dynamic dyn=100;
Console.WriteLine(dyn.GetType());
dyn=”This is a string”;
Console.WriteLine(dyn.GetType());
dyn=new Person(){FirstName=”Terry”,LastName=”Cheng”};
Console.WriteLine(dyn.GetType());
执行上面的代码,我们可以看出dyn对象实际上从System.Int32转换成System.String,然后转换成Person对象。如果dyn对象被申明为int 或者string,以上代码将不会被编译。
dynamic类型的限制:1)动态对象不支持扩展方法。2)匿名方法,λ表达式不能作为动态方法调用的参数。3)Linq也不适用于动态对象。
4 寄宿DLR 脚本运行时(Hosting the DLR ScriptRuntime):
寄宿DLR脚本运行时可以让你的应用程序有添加脚本的能力,通过将参数传入或者传出脚本,可以让你的应用程序充分利用脚本所做的工作。当前可以支持的寄宿脚本语言有IronRuby,IronPython,和JavaScript。
使用脚本运行时,你能够执行存储在文件中的一段或者全部的脚本,你可以选择合适的语言引擎或者让DLR来确定哪个引擎。你不仅可以从脚本里传入或者传出参数值,而且还可以在动态对象上调用写在脚本里的方法。
脚本运行时环境的建立:1)创建ScriptRuntime 对象。2)设置合适的脚本引擎(ScriptEngine)。3)创建ScriptSource。4)创建ScriptScope。
注:ScriptRuntime对象是脚本寄宿的开始和基础,它拥有寄宿环境的全局状态,通过静态方法CreateFromConfiguration来创建。下面是app.config文件的配置:
以IronPython脚本语言为例:
<configuration>
<configSections>
<section
name="microsoft.scripting"
type="Microsoft.Scripting.Hosting.Configuration.Section,
Microsoft.Scripting,
Version=0.9.6.10,
Culture=neutral,
PublicKeyToken=null"
requirePermission="false" />
</configSections>
<microsoft.scripting>
<languages>
<language
names="IronPython;Python;py"
extensions=".py"
displayName="IronPython 2.6 Alpha"
type="IronPython.Runtime.PythonContext,
IronPython,
Version=2.6.0.1,
Culture=neutral,
PublicKeyToken=null" />
</languages>
</microsoft.scripting>
</configuration>
5 DynamicObject and ExpandoObject对象:
1)通过继承DynamicObject或者使用ExpandoObject,你可以创建自己的动态对象。不同之处是继承DynamicObject时,你需要重写相应的方法,而ExpandoObject是一个Sealed的类,可以直接使用。
2)不能够直接创建一个空的dynamic对象,动态对象必须赋值。
比如:dynamic dyn; dyn.FirstName=”Terry”将会报错。但是使用ExpandoObject可以。
3) 如果你想在自定义的动态对象中添加属性控制,那么继承DynamicObject是首选。此外通过重写相关的方法,你能够控制自定义的对象和运行时的交互。