当前位置:  编程技术>.net/c#/asp.net

C# Dynamic关键字之:dynamic为什么比反射快的详解

    来源: 互联网  发布时间:2014-10-20

    本文导语:  Main方法如下: 代码如下:static void Main(string[] args){    dynamic str = "abcd";    Console.WriteLine(str.Length);     Console.WriteLine();    Console.WriteLine(str.Substring(1));     Console.ReadLine();}运行,结果如下: 使用reflactor 反编译下,可以看...

Main方法如下:

代码如下:

static void Main(string[] args)
{
    dynamic str = "abcd";
    Console.WriteLine(str.Length);

    Console.WriteLine();
    Console.WriteLine(str.Substring(1));


    Console.ReadLine();
}


运行,结果如下:

使用reflactor 反编译下,可以看到:

完整代码如下:

代码如下:

private static void Main(string[] args)
{
      object obj1 = "abcd";
      if (Program.o__SiteContainer0.p__Site1 == null)
      {
            Program.o__SiteContainer0.p__Site1 = CallSite.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "WriteLine", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
      }
      if (Program.o__SiteContainer0.p__Site2 == null)
      {
            Program.o__SiteContainer0.p__Site2 = CallSite.Create(Binder.GetMember(CSharpBinderFlags.None, "Length", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
      }
      Program.o__SiteContainer0.p__Site1.Target(Program.o__SiteContainer0.p__Site1, typeof(Console), Program.o__SiteContainer0.p__Site2.Target(Program.o__SiteContainer0.p__Site2, obj1));
      Console.WriteLine();
      if (Program.o__SiteContainer0.p__Site3 == null)
      {
            Program.o__SiteContainer0.p__Site3 = CallSite.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "WriteLine", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
      }
      if (Program.o__SiteContainer0.p__Site4 == null)
      {
            Program.o__SiteContainer0.p__Site4 = CallSite.Create(Binder.InvokeMember(CSharpBinderFlags.None, "Substring", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) }));
      }
      Program.o__SiteContainer0.p__Site3.Target(Program.o__SiteContainer0.p__Site3, typeof(Console), Program.o__SiteContainer0.p__Site4.Target(Program.o__SiteContainer0.p__Site4, obj1, 1));
      Console.ReadLine();
}

首先编译器会自动生成一个静态类:如下:
代码如下:

[CompilerGenerated]
private static class o__SiteContainer0
{
      // Fields
      public static CallSite p__Site1;
      public static CallSite p__Site2;
      public static CallSite p__Site3;
      public static CallSite p__Site4;
}

为什么这里有四个CallSite的对象呢?在我们的代码中

Console.WriteLine(str.Length);
Console.WriteLine();
Console.WriteLine(str.Substring(1));
一共使用了四次dynamic对象。1:Console.WriteLine(dynamic); str.Length返回dynamic2:dynamic.Length;3:Console.WriteLine(dynamic); str.Substring 返回dynamic4:dynamic.Substring(1); 1,2,3,4,分别对应上面的p_Site1,2,3,4;

因为1,3 都是无返回值的,所以是Action, 2,4都有返回值,所以是Func. 看上面的代码可能还不清楚,让我们手动的生成下代码吧:新建类SiteContainer 来取代编译器自动生成的类。

代码如下:

[CompilerGenerated]
public static class SiteContainer
{
  // Fields
  public static CallSite p__Site1;
  public static CallSite p__Site2;
  public static CallSite p__Site3;
  public static CallSite p__Site4;
}

接着看下初始化p__Site1时的方法吧:
代码如下:

if (SiteContainer.p__Site1 == null)
{
    CallSiteBinder csb= Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(
        CSharpBinderFlags.ResultDiscarded,
        "WriteLine", null, typeof(Program),
        new CSharpArgumentInfo[]
        {
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType,null),
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,null)
        });
    SiteContainer.p__Site1 = CallSite.Create(csb);
}

InvokeMember方法的签名:public static CallSiteBinder InvokeMember(CSharpBinderFlags flags, string name, IEnumerable typeArguments, Type context, IEnumerable argumentInfo); 1:在这里CSharpBinderFlags传递的是ResultDiscarded,代表结果被丢弃,   所以可以绑定到一个void的返回方法中。2:name传递的是”WriteLine”,要调用的方法的名称。3:typeArguments.类型参数的列表,传递null。4:context: 用于指示此操作的使用位置的 System.Type,在这里是Program5:argumentInfo:参数信息,   接着看看p__Site2如何初始化的吧:
代码如下:

if (SiteContainer.p__Site2 == null)
{
    CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(
        CSharpBinderFlags.None, "Length", typeof(Program),
        new CSharpArgumentInfo[]
        {
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
        });

    SiteContainer.p__Site2 = CallSite.Create(csb);
}

可以看到,和p__Site1不同的是,调用的是GetMember方法。
 
既然有了两个CallSite的对象,那么它们又是如何调用的呢??
使用CallSite.Target 就可以调用了。
 
 
 
//这是编译器生成的代码://SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), // SiteContainer.p__Site2.Target(SiteContainer.p__Site2, obj1) //); var pSite2Result = SiteContainer.p__Site2.Target(SiteContainer.p__Site2, obj1); SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), pSite2Result);

.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }

 
看看如何调用的吧:
因为SiteContainer.p__Site2,是调用Length属性
首先调用p__Site2的target方法,执行p__Site2,对象是obj1.
dlr 就会调用obj1.Length,并返回结果,所以pSite2Result=4;
接着调用p__Site1的target,来调用Console类的WriteLine方法,参数是pSite2Result.所以输出4.
 
最后来看下dynamic是如何调用Substring方法的:

Substring方法对应的是p__Site4,因为Substring方法传递了个参数1,并且有返回值,所以

p__Site4对象是:

public static CallSite p__Site4;
初始化:

代码如下:

if (SiteContainer.p__Site4 == null)
{
    CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(
        CSharpBinderFlags.None, "Substring", null, typeof(Program),
        new CSharpArgumentInfo[]
        {
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant
            | CSharpArgumentInfoFlags.UseCompileTimeType, null)                       
        });
    SiteContainer.p__Site4 = CallSite.Create(csb);
}

基本和上面的p__Site1类似,只是参数信息是:CSharpArgumentInfoFlags.Constant

因为调用了Substring(1).在编译的时候会传递1进去,而1是常量。 调用如下:

代码如下:

var subStringResult = SiteContainer.p__Site4.Target(SiteContainer.p__Site4, obj1, 1);
SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), subStringResult);

解释同上。

完整的Main函数代码如下:

代码如下:

static void Main(string[] args)
{
    object obj1 = "abcd";

    if (SiteContainer.p__Site1 == null)
    {
        CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(
            CSharpBinderFlags.ResultDiscarded,
            "WriteLine", null, typeof(Program),
            new CSharpArgumentInfo[]
            {
                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType,null),
                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,null)
            });
        SiteContainer.p__Site1 = CallSite.Create(csb);
    }

    if (SiteContainer.p__Site2 == null)
    {
        CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(
            CSharpBinderFlags.None, "Length", typeof(Program),
            new CSharpArgumentInfo[]
            {
                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
            });

        SiteContainer.p__Site2 = CallSite.Create(csb);
    }

    if (SiteContainer.p__Site4 == null)
    {
        CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(
            CSharpBinderFlags.None, "Substring", null, typeof(Program),
            new CSharpArgumentInfo[]
            {
                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null)    
            });
        SiteContainer.p__Site4 = CallSite.Create(csb);
    }

    var lengthResult = SiteContainer.p__Site2.Target(SiteContainer.p__Site2, obj1);
    SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), lengthResult);


    var subStringResult = SiteContainer.p__Site4.Target(SiteContainer.p__Site4, obj1, 1);
    SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), subStringResult);

    Console.ReadLine();
}


在这里,我没有使用p__Site3,因为p__Site3和p__Site1相同,不过为什么微软会生成4个CallSite对象,因为1 和3是完全相同的,难道是为了实现简单?? 、幸亏还有延迟初始化,否则静态字段这么多,不知道会对系统产生什么影响 运行,
结果如下:

 
从这个例子也可以知道为什么dynamic会比反射的速度要快了。
1:if(p__Site1)==null,p__Site1==xxx,并且p__Site1是静态类中的静态字段,所以有缓存效果。
2:CallSite.Target: 0 级缓存 - 基于站点历史记录专用的委托.
使用委托来调用,自然比反射又要快一些。.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }

    
 
 
 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • static_cast,dynamic_cast,reinterpret_cast,const_cast的区别及用法详解
  • static_cast,dynamic_cast,reinterpret_cast和const_cast的区别详解
  • java命名空间javax.xml.soap接口soapconstants成员方法: dynamic_soap_protocol定义参考
  • jQuery信息提示插件 Dynamic tooltip
  • dhcpd.conf中range dynamic-bootp后面如何进行分段地址书写?
  • Java Dynamic DNS Client
  • Dynamic Form Backgrounds
  • Spring Dynamic Modules
  • 请教snort中dynamic的count用法?
  • 160.243.145.61.broad.zh.gd.dynamic.163data.com.cn
  • 如何使用gcc生成dynamic objs
  • jQuery图片轮换插件 jQuery Dynamic Slideshow
  • C++ 中dynamic_cast<>的使用方法小结
  • eclipse配置tomcat开发Dynamic Web Project环境图解
  • c++ dynamic_cast与static_cast使用方法示例
  • 关于linux下dynamic_cast无法正确转换的问题
  • C++中的类型转换static_cast、dynamic_cast、const_cast和reinterpret_cast总结


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    java开源软件 iis7站长之家