(1)使用C# 4编写动态的代码

C# 4新增了一个dynamic关键字,可以用它来编写“动态”的代码。

例如,以下代码创建了一个ExpandoObject对象(注意必须定义为dynamic):

  dynamic dynamicObj = new ExpandoObject();

这一对象的奇特之处在于,我们可以随时给它增加新成员:

dynamicObj.Value = 100; //添加字段

dynamicObj.Increment = new Action(() => dynamicObj.Value++); //添加方法

这些动态添加的成员与普通的类成员用法一样:
即时通讯软件

for (int i = 0; i < 10; i++)

dynamicObj.Increment();//调用方法

Console.WriteLine("dynamicObj.Value={0}",dynamicObj.Value);//访问字段

ExpandoObject对象实现了IDictionary<string, object>接口,可看成是一个字典对象,所有动态添加的成员都是这个字典对象中的元素,这意味我们不仅可以添加新成员,还可以随时移除不再需要的成员:

//移除Increment方法

(dynamicObj as IDictionary<string, object>).Remove("Increment");

方法移除之后,再尝试访问此方法将引发RuntimeBinderException异常。
(2)使用dynamic关键字简化与COM组件交互的代码

要在.NET这个“托管世界”里调用“非托管世界”中的COM组件,我们必须通过 “互操作程序集(Interop Assembly)”作为桥梁,“互操作程序集”定义了CLR类型与COM类型之间的对应关系。

只要给.NET项目添加对“互操作程序集”的引用,就可以在.NET应用程序中创建这一程序集所包容的各种类型的实例(即COM包装器对象),对这些对象的方法调用(或对其属性的存取)将会被转发给COM组件。

以调用Word为例,在C# 4.0之前您可能经常需要编写这样的代码:

Object wordapp = new Word.Application();   //创建Word对象

Object fileName = “MyDoc.docx” ;//指定Word文档

Object argu = System.Reflection.Missing.Value;

Word.Document doc = wordapp.Documents.Open(ref fileName, ref argu,

ref argu, ref argu, ref argu, ref argu, ref argu, ref argu,

ref argu, ref argu, ref argu, ref argu, ref argu, ref argu,

ref argu, ref argu);

上述对Open()方法的调用语句只能用“恐怖”一词来形容,其原因是Word组件中的Open()方法定义了太多的参数。

C#4使用dynamic关键字,配合从Visual Basic中学来的“命名参数与可选参数”这两个新语法特性,可以写出更简洁的代码:

dynamic wordapp = new Word.Application();

dynamic doc = wordapp.Documents.Open(FileName: “MyDoc.docx”);

上述代码中省去了用不着的参数,并且可以去掉参数前的ref关键字。

当上述代码运行时,DLR会使用反射技术将dynamic表达式“绑定(bind)”到COM互操作程序集中所包容的Word.Application代理对象。
(3)C# 4动态编程技术内幕

C#4中所定义的dynamic变量可以引用以下类型的对象:

l 传统的“静态”的CLR对象。

l COM包装器对象。前面已经介绍了这方面的内容。

l 实现了IDynamicMetaObjectProvider接口的“动态对象”,ExpandoObject就是这种类型对象的实例。

l 基于DLR实现的动态语言(比如IronRuby和IronPython)所创建的对象。

从C#程序员角度来看,所有这四种对象都是一样的,都可用一个dynamic变量引用之,而DLR在程序运行时动态地将方法调用和字段存取请求“绑定”到真正的对象上。

dynamic的功能是由DLR所支撑的,是C#编译器与DLR分工合作的成果。

请看以下示例代码:

dynamic d = 100;

d++;

C#编译器在处理上述代码时,它并不去检查变量d是否可以支持自增操作,而是为其创建了一个CallSite<T>对象(<>p__Site1):

private static class <Main>o__SiteContainer0 {

public static CallSite<Func<CallSite, object, object>> <>p__Site1;

}

中文MSDN将CallSite<T>译为“动态(调用)站点”,它是DLR中的核心组件之一。

动态站点对象通过CallSite<T>.Create()方法创建, C#编译器会为其指定一个派生自CallSiteBinder的对象(称为“动态站点绑定对象”)作为其参数。

动态站点绑定对象是与具体语言相关的,比如IronPython和C#都有各自的动态站点绑定对象。

动态站点绑定对象的主要工作是将代码中的动态表达式(本例中为d++)转换为一棵“抽象语法树(AST:Abstract Syntax Tree)”,这棵语法树被称为“DLR Tree”,是在.NET 3.5所引入的LINQ表达式树的基础上扩充而来的,因此,有时又称其为“表达式树(Expression Tree)”

DLR在内部调用此表达式树的Compile()方法生成IL指令,得到一个可以被CLR所执行的委托(在本例中其类型就是Func<CallSite, object, object>)。

动态调用站点对象(本例中为<>p__Site1)有一个Target属性,它负责引用这一生成好的委托。

委托生成之后,动态表达式的执行就体现为委托的执行,其实参由C#编译器直接“写死”在IL代码中。

简化的代码示意如下(通过Reflector得到,为便于阅读,修改了变量名):

object d = 100;

object CS$0$0000 = d;

if (<>p__Site1 == null)

<>p__Site1 = CallSite<Func<CallSite, object, object>>.Create(……);

d = <>p__Site1.Target(<>p__Site1, CS$0$0000);

上述类型推断、方法绑定及IL代码生成的工作都是在程序运行时完成的。
(4)动态代码很慢吗?

动态编程语言易学易用,代码紧凑,开发灵活,但性能则一直是它的“软肋”。为了提升性能,DLR设计了一个三级缓存策略。

动态站点绑定对象会为动态调用表达式转换而成的语法树加上相应的测试条件(称为“test”),构成一个“规则(Rule)”,这个规则可以用于判断某个语法树是否可用于特定的动态调用表达式。

举个例子,请看以下这个动态表达式:

d1 + d2

如果在程序运行时d1和d2都是int类型的整数,则DLR生成的规则为:

if( d1 is int && d2 is int) //测试条件

return (int)d1+(int)d2; //语法树

DLR通过检查规则中的“测试条件”,就可以知道某个动态表达式是否可以使用此规则所包容的语法树。

“规则”是DLR缓存的主要对象。

前面介绍过的动态站点对象Target属性所引用的委托是第一级缓存,它实现的处理逻辑是这样的:

//当前处理规则,属于第1级缓存

if( d1 is int && d2 is int) //测试条件

return (int)d1+(int)d2; //满足测试条件,直接返回一个表达式树

//未命中,则在第2级、第3级缓存中查找,如果找到了,用找到的结果更新第1级缓存

return site.Update(site,d1,d2);

如果3级缓存中都没有命中的规则,则此动态站点所关联的调用站点绑定对象会尝试创建一个新的规则。如果创建新规则失败,则由当前编程语言(比如C#)所提供的默认调用站点绑定对象决定如何处理,通常的作法是抛出一个异常。

当前版本的DLR第2级缓存了10条规则,第3级则缓存了100条规则。

由于DLR自身设计了一个“规则”缓存系统,又充分利用了CLR所提供的JIT缓存(因为所有动态调用代码最终都会转换为CLR可以执行的IL指令,而CLR可以缓存这些代码),使得动态代码仅仅在第一次执行时性能较差,后续的连续调用其性能可以逼近静态代码。
3 C# 4与动态语言的集成

由于几乎所有的编程语言都可以使用抽象语法树来表达,因此,在理论上DLR支持无限多种编程语言间的互操作,在当前版本中,可以实现C#/Visual Basic与IronPython和IronRuby的互操作,相信很快会出现其他动态编程语言的DLR实现。

一个有趣的地方是当前基于DLR实现的动态编程语言都以“Iron”开头,比如IronRuby和IronPython。IronPython的设计者、DLR的架构设计师Jim Hugunin曾经在微软PDC 2008大会上解释说主要是为了避免起一个“Python.NET”或“Python for .NET”之类“微软味十足”的名字,才有了“IronPython”。他强调:“Iron”系列动态语言将严格遵循动态语言自身的标准和规范,尊重这些动态语言已有的历史和积累,不会引入一些仅限于.NET平台的新语言特性,并且这些语言的.NET实现保持开源。与此同时,Jim Hugunin指出 “Iron”系列语言能很好地与.NET现有类库、编程语言和工具集成,并且能“嵌入”到.NET宿主程序中。
(1)动态对象通讯协议

由于各种动态编程语言之间的特性相差极大,实现各语言间的互操作是个难题。为此DLR采取了一个聪明的策略,它不去尝试设计一个“通用的类型系统”(CLR就是这么干的),而是设计了一个“通用的对象通讯协议”,规定所有需要互操作的动态对象必须实现IDynamicMetaObjectProvider接口,此接口定义了一个GetMetaObject()方法,接收一个语法树对象作为参数,向外界返回一个“动态元数据(DynamicMetaObject)”对象:

DynamicMetaObject GetMetaObject(Expression parameter);

DynamicMetaObject对象向外界提供了两个重要属性:Restrictions引用一组测试条件,Expression属性则引用一个语法树。这两个属性组合起来就是可供动态站点对象缓存的“规则(Rule)”。

DLR中的“动态站点绑定对象(CallSiteBinder)”获取了DynamicMetaObject对象之后,它调用此对象所提供的各个方法创建“规则”,让“动态站点对象(CallSite<T>)”的Target属性引用它,完成动态绑定的工作。
(2)动态语言集成环境

为了方便地实现静态编程语言与各种动态编程语言间的相互集成,DLR提供了一整套称为“通用寄宿(Common Hosting)”的组件,其中包容ScriptRuntime、ScriptScope等类型。

下面我们以IronPython为例,介绍如何在C# 4开发的程序中集成动态编程语言代码。

首先需要创建一个ScriptRuntime对象,它是一个最顶层的对象,用于在一个.NET应用程序域中“嵌入”一个特定动态语言的运行环境:

ScriptRuntime pythonRuntime = Python.CreateRuntime();

接着需要创建一个ScriptEngine对象,它是动态语言代码的执行引擎:

ScriptEngine engine = pythonRuntime.GetEngine("py");

ScriptScope对象类似于C#中的命名空间,其中可以通过定义一些变量向动态代码传入数据,比如下述代码将一个C# 创建的ExpandoObject对象传给Python代码:

ScriptScope scope = pythonRuntime.CreateScope();

//C#创建动态对象

dynamic expando = new ExpandoObject();

expando.Name = "JinXuLiang"; //动态添加一个字段

//让IronPython接收C#创建的Expando对象

scope.SetVariable("ExpandoObject", expando);

string pythonCode = "print ExpandoObject.Name";

//IronPython引擎执行Python语句

engine.CreateScriptSourceFromString(pythonCode).Execute(scope);

上述示例代码是直接执行Python代码。在实际开发中,更常见的是直接执行Python文件中的代码,假设有一个Calculator.py文件,其中定义了一个Add函数:

def Add(a,b):

return a+b

则以下C#代码可以直接执行之:

ScriptRuntime pythonRuntime = Python.CreateRuntime();

dynamic pythonFile = pythonRuntime.UseFile("Calculator.py");

Console.WriteLine(pythonFile.Add(100, 200));

上述示例说明在DLR的支持之下,可以让静态编程语言使用动态语言所开发的库,反过来,基于DLR实现的动态编程语言也能使用为静态语言所设计的库,比如标准的.NET基类库。

这意味着两点:

(1)我们现在可以将“静态”和“动态”编程语言组合起来,开发出一些具有高度交互性的应用程序,使用静态编程语言搭建系统框架,使用动态编程语言实现交互性,这是一个很值得注意的应用领域。

(2)将来会出现一些“静态”“动态”编程语言同时适用的库,向实现“无所不在的复用”目标又前进了一步。

Visual Studio 2010为新的.NET编程语言F#提供了专门的项目模板,但没有为IronPython和IronRuby之类动态语言的开发提供支持,相信随着动态语言在.NET平台之上的应用日趋广泛,后继版本的Visual Studio会直接支持动态语言的开发。

关注技术文章飞秋:http://www.freeeim.com/,24小时专业转载。

【飞秋】使用C# 4编写动态的代码相关推荐

  1. 这就是飞秋下载早期的学习生涯

    这就是飞秋下载早期的学习生涯,深深地体现出陶瓷的时代特色.这段时间hongjin2的生活是困苦的,心情是苦闷的,但学习热情却是无以伦比的.现在hongjin2一个人拥有两台奔四电脑,随时可上互联网获取 ...

  2. 『飞秋』Html.Label的缺陷及补救办法

    在最近开发的项目中,应用了Html.LabelFor(TModel)来生成<lable/>标签,同时配合Html.TextBoxFor(TModel)来生成<Input/>标签 ...

  3. 为你的应用程序添加动态Java代码

    原来一直以为,JAVA程序都必须在执行前被编译,而不是在运行时可以动态加载,看了这篇文章后,才知道这么一回事,看来JAVA里面的东西没有熟悉还有的是,不要以人好像什么都懂都了. 作者:Amydeng; ...

  4. 【飞秋】ASP.NET 之 常用类、方法的超级总结,并包含动态的EXCEL导入导出功能,奉上类库源码

    最近闲了,花点几天时间将项目中常用的一些类.方法做了一下总结,希望对大家有用. 实用类:UtilityClass 包含如下方法 判断对象是否为空或NULL,如果是空或NULL返回true,否则返回fa ...

  5. 【飞秋】使用C++语言创建Silverlight中的VisualState

    Silverlight中的VisualState(可视状态)是一个非常重要的概念,使用VisualState,可以将界面的各个状态进行有效的区隔开,并进行单独的设计,并且可以在状态切换时实现动画效果, ...

  6. 飞秋2010 开发团队建设与管理的一些心得

    在软件开发的工作中,我们都要经历团队协作这个历程,有句话说的好,"软件开发是一项目团队运动",虽然这句话已经忘记是从哪本书上看的了,但这一句后的含义确让我们需要去更多的深思与实践, ...

  7. 免费软件做的不错的,这里要说一个叫《飞秋》的软件

    免费软件做的不错的,这里要说一个叫< 飞秋>的软件.   文字表情图片对话 免费的局域网即时通讯平台,支持文字.图片.表情的多人群发:支持对方离线时发送:兼容飞鸽传书. 高速文件传输 支持 ...

  8. 战线长一点的飞秋实现原理

    摘要:飞秋实现原理 2012年07月12日,让我们拭目以待,飞秋实现原理由于有惩戒箴言的作用,等级设置为15级,已成为越来越多的用户关心的话题,4个可操作角色,但是相对来说也是可以的,动漫电影的表现手 ...

  9. 《飞秋下载》介绍过的求伯君,看看!

    后来,hongjin2又编了读取wps文件的程序(当时dos下打字排版是求伯君的wps一统天下,word当时在哪里hongjin2不知道呢!< 飞秋下载>介绍过的求伯君,鲍岳桥等作为第一代 ...

最新文章

  1. 部署SQL AZURE的客户端管理工具,云计算体验之二
  2. frontpage中html编辑,FrontPage教程编辑网页
  3. 换脸系列——眼鼻口替换
  4. 影院平台搭建 - (6)一个靠谱的视频播放方案的感想
  5. 数据分析来诠释,为了“鸡”出“牛蛙”,中国家长到底能有多拼!
  6. Elasticsearch--入门-_cat命令查看节点相关信息---全文检索引擎ElasticSearch工作笔记004
  7. jquery extend中
  8. 《面向对象程序设计》第六次作业(图形化界面)
  9. win7旗舰版升级成win7SP1
  10. 树莓派4B安装中文输入法(Googlepinyin)
  11. 学术英语理工(第二版)Unit6课文翻译
  12. CST816S触摸驱动
  13. 报警后签了和解协议,还能反悔吗
  14. [转]我的IT学习生活(搜藏)
  15. 微信小程序:音乐播放器带进度条
  16. linux cma内存,【原创】(十六)Linux内存管理之CMA,
  17. MATLAB——基于图像相减的纸牌识别系统
  18. 面向对象的五大基本原则(SOLID)
  19. Cadence (Allegro) 转 Altium Designer
  20. 《一个大学生的学习笔记》

热门文章

  1. VScode中常用element语法
  2. 最优化学习笔记(十)——对偶线性规划
  3. 移动互联网数据安全蓝皮报告(2021年)
  4. json php 数组读写,PHP如何将数据写入JSON?
  5. python 通过ip获取城市_python中通过客户端IP拿到所在城市和当地天气信息—附带项目案例...
  6. java 查看堆外内存占用_如何监控和诊断JVM堆内和堆外内存使用?
  7. iap如何初始化_IAP在线升级模块详细设计说明
  8. 人事管理系统 数据流图_中国移动集中化人力资源管理系统试点上线成功
  9. RabbitMq topic
  10. 队列模拟约瑟夫问题(洛谷P1996题题解,Java语言描述)