C#高级编程六十九天----DLR简介 .在.NET中使用DLR(转载) 我也来说说Dynamic

DLR

一.近年来,在TIOBE公司每个月发布的编程语言排行榜中,C#总是能挤进前十名,而在最近十年来,C#总体上呈现上升的趋势.C#能取得这样的成绩,有很多因素,其中它在语言特性上的锐意进取让人印象深刻.

 

 

 

C#4动态功能是Dynamic Language Runtime(动态语言运行时,DLR)的一部分.DLR是添加到CLR的一系列服务,它允许添加动态语言,如Ruby和Python,并使C#具备和这些动态语言相同的某些功能.

 

 

动态编程语言并非什么新鲜事物,早在面向对象编程语言成为主流之前,人们就已经使用动态编程语言来开发了.及时在JAVA,C#,C++等面向对象编程语言繁荣兴旺,大行于世的年代,动态编程语言也在”悄悄”的攻城略地,占据了相当的开发领域,比如JS也已成为了web客户端事实上的主流语言.

最近这几年,动态语言变得很火,比如Python,Ruby.

这里有一个问题,为什么我们需要在开发中应用动态编程语言?与C#he JAVA这类已经变得非常成熟且功能强大的静态类型编程语言相比,动态编程语言有何优势?

简单地说,使用动态编程语言开发拥有以下特性:

1.支持REPL(read-evaluate-print Loop:读入->执行->输出,循环迭代)的开发模式,这个过程就简洁明了了,直指问题的核心.

案例:我们使用IronPython[2]变成计算1+2+...+100,我们可以快速的输入一段完成累加求和的代码,然后马上就可以求和:

 

 

如果使用C#开发貌似就麻烦的多了,得先使用VS创建一个项目,然后向其中添加一个类,在类中写一个方法完成求和的功能,在编译调用这一方法的代码,编译,排错,最后才能得到结果.

 

2.扩展方便.用户可以随时对代码进行调整,需要什么功能直接往动态对象上”加”就是了,不是的时候可以一处他们.而且这种修改可以马上生效,并不像C#那样必须先修改类的定义和声明,编译之后新方法才能使用.

 

换句话说:使用动态语言编程,不需要“重量级”的OOAD,整个开发过程迭代迅速而从不拖泥带水。

 

3.动态编程语言的类型解析实在运行时完成的,可以省去许多不必要的类型转换代码,因此,与静态类型编程语言相比,动态类型编程语言写的代码往往更紧凑,量更少.

 

当然了,动态语言的缺点也是有的:

1.代码中的许多错误要等到运行的时候才能发现,而且需要特定的运行环境支持,对其进行测试不太方便,也不支持许多用于提升代码质量的各种软件工程工具,因此不太适合开发规模大,包含复杂逻辑的应用系统.

2.与静态语言相比,动态语言编写的程序性能较低.不过随着计算机硬件技术的不断进步,比如多核CPU的广发应用,动态编程语言引起和运行环境不断的优化,动态编程语言编写的程序性能不断提升,在特定的应用场景中,甚至可以逼近静态语言编写的程序.

 

 

 

二.拥抱”动态编程”特征的C#4

为了让C#,VB等.NET编程语言能具备动态编程语言的特性,.NET4引入了一个DLR:

 

 

 

DLR运行于CLR之上,提供了一个动态语言的运行环境,从而允许Python,Ruby等动态语言编写的程序在.NET平台上运行,同时,现有的.NET静态类型编程语言,比如C#和VB,也可以利用DLR而拥有一些动态编程语言的特征.

 

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

 

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

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

            //这里需要添加命名空间System.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组件,我们必须通过”互操作程序集(InteropAssembly)”作为桥梁,”互操作程序集”定义了CLR类型与COM类型之间的对应关系.

 

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

 

以调试word为例,在C#4以前您可能经常需要编写这样的代码:

             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()方法的调用语句只能用一句”JB”来形容,其原因是word组件中的Open()方法定义了太多的参数.

 

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

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变量可以引用以下类型的对象:

a.传统的”静态”的CLR对象

b.COM包装器对象.

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

d.基于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_SiteContainer(){

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可以缓存这些代码),使得动态代码仅仅在第一次执行时性能较差,后续的连续调用其性能可以逼近静态代码.

 

三.C#4与动态语言的继承

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

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

 

(1)动态对象通讯协议

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

DynamicMetaObject GetMetaObject(Expression parameter);

 

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

 

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

 

(2)动态语言集成环境

为了方便的实现静态语言与各种动态语言间的相互集成,DLR提供了一整套称为”通用寄宿”的组件,其中包含ScriptRuntime,ScriptScope等类型.

 

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

将来回出现一些静态,动态编程语言同时适用的库,像实现”无所不在的复用”目标又前进了一步.

 

 

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

         从C# 1.0~4.0所走过的路,可以很清晰地看到它的发展轨迹,得到这样的一个结论:

         未来的编程语言应该是多范式的,具有高度的可组合性,在一个项目或产品中组合多个编程语言、使用多种编程范式会变得越来越普遍。

         我们可以推断C#的后继版本将会在此条道路上越走越远……

 

 

 

什么是DLR呢?

DLR(Dynamic Language Runtime),是微软主导的一个开源项目.为,NET应用程序,提供脚本支持.目前版本为0.9,你可以从Codeplex获得源码.

 

 

DLR主要提供以下三个功能:

1.语言实现服务提供语言的互操作性

2.动态语言运行时服务提供动态调用支持

3.公共脚本宿主

 

依托这些模块,您可以非常轻松的做下面这些事

1.为您现有的.NET应用程序,加入脚本支持

2.为您现有的语言,提供动态知己

3.为任何对象提供动态操作支持

4.在您的架构中提供脚本语言.

 

 

 

 

 

.在.NET中使用DLR(转载)

 

转载自:http://chen1996.blog.163.com/blog/static/4441005220091117102310427/

前言

    看到许多朋友写过,在C#中调用DLR脚本的方法,但没有一个说的完整。如今我要说一个详细完整的,希望能对您有所帮助。本文,主要通过C#与IronPython脚本,来体现.NET与脚本互操作的过程。

什么是DLR

    DLR(Dynamic Language Runtime),是微软主导的一个开源项目。为.NET应用程序,提供了脚本技持。目前版本为0.9,你可以从Codeplex获得源吗。具体可以看我的博文《研究研究DLR》

总览

image1

    应用程序执行脚本的方法有很多种:

  1. 通过ScriptRuntime.ExcuteFile获得ScriptScope
  2. 通过ScriptRuntime.UseFile获得ScriptScope
  3. 通过ScriptRuntime.CreateScope获得ScriptScope,再执行ScripeScope.Execute或ScripeScope.IncludeFile
  4. 通过ScriptRuntime.GetEngine或ScriptRuntime.GetEngineByFileName获得ScriptEngine。调用ScriptEngine的CreateScriptSourceFromString或CreateScriptSourceFromFile或CreateScriptSourceFromStream创建ScriptSource,再执行ScriptSource.Execute。
  5. 有了ScriptSource也不一定要Execute,可以先调用Compile,产生CompiledCode,最后调用CompiledCode.Execute。
引用DLR

    首先,当然要获得DLR模块对应的DLL。您可以从Codeplex,下载取得。内容如下: 
Image2
我在工程目录下面建了一个DLR目录,并把这些文件都Copy进去。然后在解决方案资源管理器视图中,右键“引用”选择“添加引用” 
Image3 
点击“浏览”如下图 
Image4 
将“Microsoft.Scripting.Core.dll”“Microsoft.Scripting.dll”“Microsoft.Scripting.ExtensionAttribute.dll”等文件加入引用。我也不想说的更细了,具体参见Visual Studio的帮助文档。

    被引用的文件编译时会自己Copy到Bin目录去的,但没引用的文件是不会Copy的。我的做法是将这些文件加入工程,然后设置Copy。由于我只要使用Python语言,所以我只Copy了“IronPython.dll”、“IronPython.Modules.dll”与“App.Config”几个文件。

初始化

    引用了DLR之后,就要对DLR进行初始化。

  1. 首先要使用namespace 
    using Microsoft.Scripting.Hosting;
  2. 接着定义与创建ScriptRuntime 
    ScriptRuntime env = ScriptRuntime.CreateFromConfiguration(); 
    ScriptScope scope;
  3. 加载脚本,我在窗体的构造函数里,加入如下标黄的代码

public Window1() 

    InitializeComponent(); 
Assembly assembly = Assembly.GetAssembly(typeof(Contact)); 
    env.LoadAssembly(assembly); 
    scope = env.ExecuteFile("Test.py"); 
}

    前两行代码,执行ScriptRuntime.LoadAssembly,使脚本能直接使用当前程序集中的Class。接下来执行ScriptRuntime.ExecuteFile,运行Test.py脚本。

调用脚本的函数

    要调用脚本的函数,首先要定义一个方法的委托。通过委托调用脚本,是最高效的方式。当然,也可以用DynamicObject的TryInvoke方法,调用脚本的函数。这里我介绍委托的方式。

  1. 定义委托 
    delegate void ScriptOnLoad(Window window); 
    委托的参数形式,与脚本的参数一致。
  2. 调用脚本的函数 
    ScriptOnLoad fun; 
    if (scope.TryGetVariable<ScriptOnLoad>("OnLoad", out fun)) 
        fun(this); 
    以上代码,TryGetVariable根椐函数名,获得委托。然后,再通过委托就可以直接调用脚本了。当然,您也可以将委托存起来,从而高效的调用函数。
脚本调用C#

下面看看Test.py脚本。

import WpfApplication 
def OnLoad(Window): 
    dataProvider = Window.FindResource("myDateCollectionDataSource") 
    data = dataProvider.Data; 
    c = WpfApplication.Contact("Chen1996", "Chen1996是个聪明人") 
    data.Add(c)

    这个脚本不长,但有三个关键点值得关注。

    第一行的import语句,相当于C#的using。其中WpfApplication,是这个C#程序的名字空间。之前初始化时调用LoadAssembly,还记得吗?ScriptRuntime的这个函数,就是用来加载程序集供脚本使用的。

    接下来第三行,Window.FindResource,非常简单的调用C#中的方法。DLR提供得,.NET原生支持就是好。后面第四行与第六行也都一样。这里并不依赖,初始化时通过LoadAssembly加载的程序集,因为一切都源参数Window这个对像。

    第四行,创建了一个WpfApplication.Contact的对象。WpfApplication,就是之前初始化时加载的程序集。为了要使用这个程序集里的类,就必须先加载。然后,就可以像使用脚本自己的类型一样使用了。还是得益于DLR,为我们提供的.NET原生支持,哈哈。

总之,C#与Python之间互操作,非常的简单又高效。同理通过这个例子,完全可以应用到所有的脚本语言及.NET语言。

转载自:http://chen1996.blog.163.com/blog/static/4441005220091117102310427/

 

 

看了很多人讨论Dynamic。不禁自己也想挖掘下。下面把自己的体会分享给大家

 

1.Dynamic关键字是为了方便访问某个对象。而跟DLR没太大关系。

使用了dynamic关键字创建的对象实际上是一个object. 使用.net 4.0以下的Reflector就可以看到.

使用dynamic关键字后编译器将会将这个对象后面的PropertyName翻译成相应Binder调用。因此语法检查器会忽略检查此对象是否包含PropertyName.

真正的跟DLR有关的是在System.Dynamic下的类型。

大家可以实验一个叫ExpandoObject的东西

1
2
3
4
5
6
7
8
private  static  void  Main( string [] args)
{
     dynamic expandoObject = new  ExpandoObject(); expandoObject.
     PropertyA = "PropertyA" ;
     expandoObject.PropertyB = 2010;
     Console.WriteLine(expandoObject.PropertyA);
     Console.WriteLine(expandoObject.PropertyB);
}


这个时候用dynamic是不是有点动态语言的感觉了?所以说 dynamic不是DLR的实现,
但要用DLR在C#里最好的途径可能就是使用dynimic了。


 

2.Dynamic关键字是一个编译器做的语法糖

  

请看如下代码:

原始代码

 
<blockquote><pre class = "brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;" > public  class  Program
     {
         static  void  Main( string [] args)
         {
 
             Method1();
             Method2();
             Method3();
             Method4();
         }
 
 
         private  static  void  Method1()
         {
             dynamic d = new  TestClass();
             d.TestProperty = "" ;
         }
         private  static  void  Method2()
         {
             TestClass t = new  TestClass();
             dynamic d1 = t;
             dynamic d2 = t;
             d1.TestProperty = "" ;
             d2.TestProperty = "" ;
 
         }
         private  static  void  Method3()
         {
             dynamic d = new  TestClass();
             for  ( int  i = 0; i < 100; i++)
             {
                 d.TestProperty = i.ToString();
 
             }
         }
 
 
         private  static  void  Method4()
         {
             
             for  ( int  i = 0; i < 100; i++)
             {
                 dynamic d = new  TestClass();
                 d.TestProperty = i.ToString();
 
             }
         }
 
    class  TestClass
     {
         public  string  TestProperty { get ; set ; }
     }</pre></blockquote>



用3.5语法反编译的
其实上面也都说的很清楚了 编译器会把dynamic编译在一个和dynamic所在函数名有关的Static SiteContainer

<Method1>o__SiteContainer0
<Method2>o__SiteContainer2 …等

 

而且是一个dynamic生成一个Site .装在对应的Container中。

下面我们来看Method1 反编译后

  
1
2
3
4
5
6
7
8
9
private  static  void  Method1()
{
     object  d = new  TestClass();
     if  (<Method1>o__SiteContainer0.<>p__Site1 == null )
     {
         <Method1>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object , string , object >>.Create(Binder.SetMember(CSharpBinderFlags.None, "TestProperty" , typeof (Program), new  CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null ), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null ) }));
     }
     <Method1>o__SiteContainer0.<>p__Site1.Target(<Method1>o__SiteContainer0.<>p__Site1, d, "" );
}

可以看出d其实是个Object了访问属性通过Site实现,而且这里的Site判空,意味着可以缓存。

Method2反编译后

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private  static  void  Method2()
{
     TestClass t = new  TestClass();
     object  d1 = t;
     object  d2 = t;
     if  (<Method2>o__SiteContainer2.<>p__Site3 == null )
     {
         <Method2>o__SiteContainer2.<>p__Site3 = CallSite<Func<CallSite, object , string , object >>.Create(Binder.SetMember(CSharpBinderFlags.None, "TestProperty" , typeof (Program), new  CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null ), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null ) }));
     }
     <Method2>o__SiteContainer2.<>p__Site3.Target(<Method2>o__SiteContainer2.<>p__Site3, d1, "" );
     if  (<Method2>o__SiteContainer2.<>p__Site4 == null )
     {
         <Method2>o__SiteContainer2.<>p__Site4 = CallSite<Func<CallSite, object , string , object >>.Create(Binder.SetMember(CSharpBinderFlags.None, "TestProperty" , typeof (Program), new  CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null ), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null ) }));
     }
     <Method2>o__SiteContainer2.<>p__Site4.Target(<Method2>o__SiteContainer2.<>p__Site4, d2, "" );
}
 
虽然 d1 d2 都指向了 同一个对象t.但这里还是创建了两个Site。可见出现了多少个dynamic就会创建多少个site.<br><br>再看Method3和Method4
1
  

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private  static  void  Method3()
     {
         object  d = new  TestClass();
         for  ( int  i = 0; i < 100; i++)
         {
             if  (<Method3>o__SiteContainer5.<>p__Site6 == null )
             {
                 <Method3>o__SiteContainer5.<>p__Site6 = CallSite<Func<CallSite, object , string , object >>.Create(Binder.SetMember(CSharpBinderFlags.None, "TestProperty" , typeof (Program), new  CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null ), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null ) }));
             }
             <Method3>o__SiteContainer5.<>p__Site6.Target(<Method3>o__SiteContainer5.<>p__Site6, d, i.ToString());
         }
     }
 
     private  static  void  Method4()
     {
         for  ( int  i = 0; i < 100; i++)
         {
             object  d = new  TestClass();
             if  (<Method4>o__SiteContainer7.<>p__Site8 == null )
             {
                 <Method4>o__SiteContainer7.<>p__Site8 = CallSite<Func<CallSite, object , string , object >>.Create(Binder.SetMember(CSharpBinderFlags.None, "TestProperty" , typeof (Program), new  CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null ), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null ) }));
             }
             <Method4>o__SiteContainer7.<>p__Site8.Target(<Method4>o__SiteContainer7.<>p__Site8, d, i.ToString());
         }
     }


可见dynamic写在循环里和循环外都是一样的。因为编译器只看到一个dynamic。只生成了一个site.由于site一样且经过缓存,
可以猜想性能不会相差太。

3.Dynamic做了会做缓存,加速访问

由于Site和SiteContainer都是Staic的,所以凡是重复对一个dynamic操作多次都会受益于这种cache。眼看要下班了。笔先收一下,有时间再写:-)

转载于:https://www.cnblogs.com/cjm123/p/9076454.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值