源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

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

  • 时间:2022-01-26 09:22 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:C# Dynamic关键字之:dynamic为什么比反射快的详解
[b]Main方法如下: [/b]
[u]复制代码[/u] 代码如下:
static void Main(string[] args) {     dynamic str = "abcd";     Console.WriteLine(str.Length);     Console.WriteLine();     Console.WriteLine(str.Substring(1));     Console.ReadLine(); }
[b]运行,结果如下: [/b] [img]http://files.jb51.net/file_images/article/201305/2013051409520635.jpg[/img] 使用reflactor 反编译下,可以看到: [b]完整代码如下: [/b]
[u]复制代码[/u] 代码如下:
private static void Main(string[] args) {       object obj1 = "abcd";       if (Program.<Main>o__SiteContainer0.<>p__Site1 == null)       {             Program.<Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.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.<Main>o__SiteContainer0.<>p__Site2 == null)       {             Program.<Main>o__SiteContainer0.<>p__Site2 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Length", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));       }       Program.<Main>o__SiteContainer0.<>p__Site1.Target(Program.<Main>o__SiteContainer0.<>p__Site1, typeof(Console), Program.<Main>o__SiteContainer0.<>p__Site2.Target(Program.<Main>o__SiteContainer0.<>p__Site2, obj1));       Console.WriteLine();       if (Program.<Main>o__SiteContainer0.<>p__Site3 == null)       {             Program.<Main>o__SiteContainer0.<>p__Site3 = CallSite<Action<CallSite, Type, object>>.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.<Main>o__SiteContainer0.<>p__Site4 == null)       {             Program.<Main>o__SiteContainer0.<>p__Site4 = CallSite<Func<CallSite, object, int, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.None, "Substring", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) }));       }       Program.<Main>o__SiteContainer0.<>p__Site3.Target(Program.<Main>o__SiteContainer0.<>p__Site3, typeof(Console), Program.<Main>o__SiteContainer0.<>p__Site4.Target(Program.<Main>o__SiteContainer0.<>p__Site4, obj1, 1));       Console.ReadLine(); }
首先编译器会自动生成一个静态类:如下:
[u]复制代码[/u] 代码如下:
[CompilerGenerated] private static class <Main>o__SiteContainer0 {       // Fields       public static CallSite<Action<CallSite, Type, object>> <>p__Site1;       public static CallSite<Func<CallSite, object, object>> <>p__Site2;       public static CallSite<Action<CallSite, Type, object>> <>p__Site3;       public static CallSite<Func<CallSite, object, int, object>> <>p__Site4; }
为什么这里有四个CallSite<T>的对象呢?在我们的代码中 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 来取代编译器自动生成的类。
[u]复制代码[/u] 代码如下:
[CompilerGenerated] public static class SiteContainer {   // Fields   public static CallSite<Action<CallSite, Type, object>> p__Site1;   public static CallSite<Func<CallSite, object, object>> p__Site2;   public static CallSite<Action<CallSite, Type, object>> p__Site3;   public static CallSite<Func<CallSite, object, int, object>> p__Site4; }
接着看下初始化p__Site1时的方法吧:
[u]复制代码[/u] 代码如下:
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<Action<CallSite, Type, object>>.Create(csb); }
InvokeMember方法的签名:public static CallSiteBinder InvokeMember(CSharpBinderFlags flags, string name, IEnumerable<Type> typeArguments, Type context, IEnumerable<CSharpArgumentInfo> argumentInfo); 1:在这里CSharpBinderFlags传递的是ResultDiscarded,代表结果被丢弃,   所以可以绑定到一个void的返回方法中。2:name传递的是”WriteLine”,要调用的方法的名称。3:typeArguments.类型参数的列表,传递null。4:context: 用于指示此操作的使用位置的 System.Type,在这里是Program5:argumentInfo:参数信息,   接着看看p__Site2如何初始化的吧:
[u]复制代码[/u] 代码如下:
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<Func<CallSite, object, object>>.Create(csb); }
可以看到,和p__Site1不同的是,调用的是GetMember方法。
 
既然有了两个CallSite<T>的对象,那么它们又是如何调用的呢??
使用CallSite<T>.Target 就可以调用了。
 
[img]http://files.jb51.net/file_images/article/201305/2013051409520636.png[/img]
 
 
//这是编译器生成的代码://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);
 
[b]看看如何调用的吧:[/b]
因为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<Func<CallSite, object, int, object>> p__Site4; 初始化:
[u]复制代码[/u] 代码如下:
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<Func<CallSite, object, int, object>>.Create(csb); }
基本和上面的p__Site1类似,只是参数信息是:CSharpArgumentInfoFlags.Constant \ 因为调用了Substring(1).在编译的时候会传递1进去,而1是常量。 调用如下:
[u]复制代码[/u] 代码如下:
var subStringResult = SiteContainer.p__Site4.Target(SiteContainer.p__Site4, obj1, 1); SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), subStringResult);
解释同上。 完整的Main函数代码如下:
[u]复制代码[/u] 代码如下:
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<Action<CallSite, Type, object>>.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<Func<CallSite, object, object>>.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<Func<CallSite, object, int, object>>.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<T>对象,因为1 和3是完全相同的,难道是为了实现简单?? 、幸亏还有延迟初始化,否则静态字段这么多,不知道会对系统产生什么影响 运行, 结果如下:  [img]http://files.jb51.net/file_images/article/201305/2013051409520637.jpg[/img]
从这个例子也可以知道[b]为什么dynamic会比反射的速度要快了。[/b]
1:if(p__Site1)==null,p__Site1==xxx,并且p__Site1是静态类中的静态字段,所以有缓存效果。
2:CallSite<T>.Target: 0 级缓存 - 基于站点历史记录专用的委托.
使用委托来调用,自然比反射又要快一些。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部