找回密码
 立即注册
首页 业界区 业界 Framework 4.0 新关键字dynamic 之我见(一)

Framework 4.0 新关键字dynamic 之我见(一)

轧岔 2025-5-29 20:29:48
大家好,好久没有写博客了,最近一段时间工作也比较忙,不过我还是会在空余时间去学习一些东西。
微软在这个星期一,开放了VS2010和Framework4.0的Beta1版本的下载,所以我也花了1天的时间进行了下载和安装,因为系统现在是windows7,而且这次版本也是beta版本,所以把它安装在了虚拟机上,虽然只设置了1G的内存,不过跑起来还非常让人满意,没有像其他兄弟说的,很吃内存,很废cpu。
其实先前已经使用过CTP版本了,也一直对新特性在做研究,在第一时间下载了beta版本后,发现其实和CTP版本区别不是很大。好了,废话不说了,说说今天的主题吧。
在Framework 4.0 中,微软加入了新的关键字:dynamic  根据字的中文含义,我们就知道了,动态,一切都为动态。有了这个关键字,我们在写代码时就可以不用确定某个变量、属性、方法(不包含void方法,文中所说的方法都是不包含void的)的类型了,一切都交给Framework吧。或许有人会说更var好像一样,其实两者一点都不一样,这会在后面跟大家说说。先来看一段简单的代码:
  static void Main(string[] args)
        {
            dynamic dynamicValue;
            dynamicValue = DateTime.Now;
                Console.WriteLine(dynamicValue.ToString("yyyy-MM-dd"));
                Console.WriteLine(dynamicValue.GetType());
                Console.Read();
        }
非常简单的一段代码,我们用dynamic定义了一个变量,然后给它赋了一个时间类型的值,随后打印DateTime.ToString()方法,再打印这个动态变量的类型出来。这里要说一点,也是非常重要的一点:
Dynamic 在没有运行的时候,是一个Object类型,其实也可以说没有Type的,它是在Runtime时才被确定是那种类型,所以这里的.ToString()方法,在IDE中是没有任何智能感知的,有点回到记事本的时代了,呵呵。
其实在CTP版本中,已经是这样了,不过我觉得,虽然他在编译时不能确定他的类型,但所有的类型都是继承于Object类型的,为什么智能感知没有把Object的几个共有方法给感知出来呢???(我等了一个版本还是这样,真有点失望)。
那我们来看看,到底程序为什么那么慢吧。用IL DASM看看。
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       396 (0x18c)
  .maxstack  12
  .locals init ([0] object dynamicValue,
           [1] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000)
  IL_0000:  nop
  IL_0001:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
  IL_0006:  box        [mscorlib]System.DateTime
  IL_000b:  stloc.0
  IL_000c:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1 ConsoleApplication1.Program/'o__SiteContainer0'::'p__Site1'
  IL_0011:  brtrue.s   IL_0052
  IL_0013:  ldc.i4.0
  IL_0014:  ldstr      "WriteLine"
  IL_0019:  ldtoken    ConsoleApplication1.Program
  IL_001e:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_0023:  ldnull
  IL_0024:  ldc.i4.2
  IL_0025:  newarr     [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
  IL_002a:  stloc.1
  IL_002b:  ldloc.1
  IL_002c:  ldc.i4.0
  IL_002d:  ldc.i4.s   33
  IL_002f:  ldnull
  IL_0030:  newobj     instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
                                                                                                                string)
  IL_0035:  stelem.ref
  IL_0036:  ldloc.1
  IL_0037:  ldc.i4.1
  IL_0038:  ldc.i4.0
  IL_0039:  ldnull
  IL_003a:  newobj     instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
                                                                                                                string)
  IL_003f:  stelem.ref
  IL_0040:  ldloc.1
  IL_0041:  newobj     instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpCallFlags,
                                                                                                                      string,
                                                                                                                      class [mscorlib]System.Type,
                                                                                                                      class [mscorlib]System.Collections.Generic.IEnumerable`1,
                                                                                                                      class
//省略N行
  IL_0093:  stelem.ref
  IL_0094:  ldloc.1
  IL_0095:  ldc.i4.1
  IL_0096:  ldc.i4.3
  IL_0097:  ldnull
  IL_0098:  newobj     instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
                                                                                                                string)
  IL_009d:  stelem.ref
  IL_009e:  ldloc.1
  IL_009f:  newobj     instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpCallFlags,
                                                                                                                      string,
                                                                                                                      class [mscorlib]System.Type,
                                                                                                                      class [mscorlib]System.Collections.Generic.IEnumerable`1,
                                                                                                                      class [mscorlib]System.Collections.Generic.IEnumerable`1)
  IL_00a4:  call       class [System.Core]System.Runtime.CompilerServices.CallSite`1 class [System.Core]System.Runtime.CompilerServices.CallSite`1::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
  IL_00a9:  stsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1 ConsoleApplication1.Program/'o__SiteContainer0'::'p__Site2'
  IL_00ae:  br.s       IL_00b0
  IL_00b0:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1 ConsoleApplication1.Program/'o__SiteContainer0'::'p__Site2'
  IL_00b5:  ldfld      !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1::Target
  IL_00ba:  ldsfld     class [System.Core]System.Runtime.CompilerServices.CallSite`1 ConsoleApplication1.Program/'o__SiteContainer0'::'p__Site2'
  IL_00bf:  ldloc.0
  IL_00c0:  ldstr      "yyyy-MM-dd"
  IL_00c5:  callvirt   instance !3 class [mscorlib]System.Func`4::Invoke(!0,
                                                                                                                                                           !1,
                                                                                                                                                           !2)
  IL_00ca:  callvirt   instance void class [mscorlib]System.Action`3::Invoke(!0,
                                                                                                                                                                             !1,
                                                                                                                                                                             !2)
                                                         //再次省略N行
  IL_0184:  nop
  IL_0185:  call       int32 [mscorlib]System.Console::Read()
  IL_018a:  pop
  IL_018b:  ret
} // end of method Program::Main
 
 
晕死了,那么一大推东西,我们先看看初始化吧,原来编译器在这里把dynamic的变量类型定义成了object,因为是不确定的类型,所以。。。。它把System.Type进行迭代了(大概是这么个意思吧)。我的理解是,它先定义成object类型,然后在Runtime时,在用Invoke去调用ToString方法,省略的部分还有很多,其实都是因为它的不确定性,动态特性,所以把所有可能的类型都列举了出来,然后通过在runtime 的时候再判断和中类型,Invoke相应的方法。
 
现在知道了吧,为什么会这么慢,初始是object Type 免不了要装箱、拆箱,还要Invoke等,能不慢吗?不过测试下来,如果你用了一个Int类型的话,程序会明显的快很多,其中的原因,大家也可以研究一下。
Dynamic虽然是个好东西,不过因为很多时候的不确定因素,让程序在第一次运行的时候会造成很大程度的性能损耗,所以我建议大家一定要慎用,而且在你使用了dynamic类型后,因为它的动态特性,你将失去智能提示这个优越的功能。当然,
Dynamic也有它的好处,因为只需要在运行时第一次确定好类型后,它会变成强类型,这样在后面的运行中,会大大提高效率,而且使用起来也比较方便,免去了烦人的拆箱、装箱工作。
 
今天最后说说和var跟dynamic的区别,我们都知道var能在编译时确定类型,而且也有智能感知,但是var只能在局部使用(方法体),而且必须初始时赋予它值,它才能在编译时去确定是何种类型,不过他们都有一个特点,就是为了程序在后面的运行时,所有的类型都是强类型,至于强类型的好处,大家可以找找博客园中其他大大的一些好文章。
 
很晚了,今天就到这里了,后面的文章会谈谈dynamic在其他方面的性能比较,不过总体下来不是很理想,有点鸡肋的感觉了,感觉微软在这块做的真的不是很好,呵呵。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册