博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈Dynamic 关键字系列之四:dynamic为什么比反射快
阅读量:6871 次
发布时间:2019-06-26

本文共 9174 字,大约阅读时间需要 30 分钟。

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;}

 

在我们的代码中

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

一共使用了四次dynamic对象。
1:Console.WriteLine(dynamic); str.Length返回dynamic
2:dynamic.Length;
3:Console.WriteLine(dynamic); str.Substring 返回dynamic
4:dynamic.Substring(1);
 

1,2,3,4,分别对应上面的<>p_Site1,2,3,4;

 
 
看上面的代码可能还不清楚,让我们手动的生成下代码吧:

新建类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;}

 

接着看下初始化时的方法吧:
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,在这里是Program
5:argumentInfo:参数信息,
 
 
 
接着看看如何初始化的吧:
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);}

 

可以看到,和不同的是,。
 
 
使用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);
 
 
因为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是完全相同的, 、
幸亏还有延迟初始化,否则静态字段这么多,不知道会对系统产生什么影响
 
运行,结果如下:
 
 
 
从这个例子也可以知道
1:if(p__Site1)==null,p__Site1==xxx,并且p__Site1是静态类中的静态字段,所以有缓存效果。
2:CallSite
.Target: 0 级缓存 - 基于站点历史记录专用的委托.
使用委托来调用,自然比反射又要快一些。
 
本文转自LoveJenny博客园博客,原文链接:http://www.cnblogs.com/LoveJenny/archive/2011/07/07/2100416.html,如需转载请自行联系原作者
你可能感兴趣的文章
Centos 7 telnet 详解
查看>>
零元学Expression Design 4 - Chapter 6 教你如何在5分钟内做出文字立体感效果
查看>>
ELK+MySQL出现大量重复记录问题处理
查看>>
WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口)
查看>>
随机器构建
查看>>
golang学习笔记 ----读写文件
查看>>
如何将MathType嵌入Word 2016
查看>>
JAVA8 ARRAY、LIST操作 汇【5】)- JAVA8 LAMBDA LIST统计(求和、最大、最小、平均)...
查看>>
通过Nginx反向代理之后客户端验证码session不一致造成无法验证通过的问题解决...
查看>>
[python] PyMouse、PyKeyboard用python操作鼠标和键盘
查看>>
待整理
查看>>
(筆記) DE2與SDRAM相關資料總整理 (SOC) (DE2)
查看>>
(原創) 如何以10進位顯示8位數的七段顯示器? (SOC) (Verilog) (DE2)
查看>>
MetaModelEngine:元模型引擎开发思路
查看>>
STM32对内部Flash的保护措施
查看>>
QT练习4:编写一个查找对话框
查看>>
三道笔试题
查看>>
提升软件开发者生产力的 10 个提示
查看>>
利用Ffmpeg获得flv视频缩略图和视频时间的代码
查看>>
Markdown 11种基本语法
查看>>