独上高楼网站
  •    你所在位置:首页 VS.netC#基础知识〉c#4.0新特性之一: Dynamic Lookup (1)
  • c#4.0新特性之一: Dynamic Lookup (1)
  • 作者:hanbing  文章来源:www.cnblogs.com  发布日期:2008-11-03  浏览次数:92
  • 打印这篇文章
  • 废话不多说,直接开始。先看程序:

    Code
    1class Program
    2{
    3 static void Main(string[] args)
    4 {
    5 dynamic foo1 = new Foo();
    6        foo1.Do1();
    7        foo1.Do2();
    8 foo1.KissFanweixiao();
    9    }
    10}
    11
    12public class Foo
    13{
    14 public void Do1() { Console.WriteLine("fanweixiao calls do1"); }
    15 public void Do2() { Console.WriteLine("fanweixiao calls do2"); }
    16}

    这段代码在vs2010中可以编译通过。但是在运行的时候会报错。这是必然,KissFanweixiao()这个方法无中生有嘛。

    这里注意到这是个RuntimeBinderException,而内容是不能找到KissFanweixiao的符号。

    dynamic这个关键字看起来跟3.0增加的var很像,但是从IL的角度上来看,就是天壤之别了,毕竟var是编译时就能确定的东西,而dynamic追求的就是在运行时再决定究竟是个什么东西。我们还是先注释掉foo1.KissFanweixiao();这一句,使程序可以正常运行,然后看ILDASM的结果:

    多出一个

    o__SiteContainer0类,这个类下的<>p__Site1...和<>p__Site2...对应着Do1()和Do2()两个方法的Invoke。再细看此时的Main函数:

    Code
    .method private hidebysig static void  Main(string[] args) cil managed
    {
    .entrypoint
    // Code size       139 (0x8b)
    .maxstack 7
    .locals init ([0] object foo1)
    IL_0000: newobj instance void LearnCSharp4.Foo::.ctor()
    IL_0005: stloc.0
    IL_0006: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'

    o__SiteContainer0'::'<>p__Site1'
    IL_000b: brtrue.s   IL_0033
    IL_000d: call class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder::GetInstance()
    IL_0012: ldc.i4.0
    IL_0013: ldc.i4.0
    IL_0014: ldstr "Do1"
    IL_0019: ldtoken    [mscorlib]System.Object
    IL_001e: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_0023: ldnull
    IL_0024: newobj instance void [System.Core]Microsoft.CSharp.RuntimeBinder.CSharpCallPayload::.ctor(class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder,
    bool,
    bool,
    string,
    class [mscorlib]System.Type,
    class [mscorlib]System.Type[])
    IL_0029: call class [System.Core]System.Scripting.Actions.CallSite`1 class [System.Core]System.Scripting.Actions.CallSite`1>::Create(class [System.Core]System.Scripting.Actions.CallSiteBinder)
    IL_002e: stsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site1'
    IL_0033: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site1'
    IL_0038: ldfld      !0 class [System.Core]System.Scripting.Actions.CallSite`1>::Target
    IL_003d: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site1'
    IL_0042: ldloc.0
    IL_0043: callvirt instance void class [System.Core]System.Action`2::Invoke(!0,
                                                                                                                                                 !1)
    IL_0048: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site2'
    IL_004d: brtrue.s   IL_0075
    IL_004f: call class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder::GetInstance()
    IL_0054: ldc.i4.0
    IL_0055: ldc.i4.0
    IL_0056: ldstr "Do2"
    IL_005b: ldtoken    [mscorlib]System.Object
    IL_0060: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_0065: ldnull
    IL_0066: newobj instance void [System.Core]Microsoft.CSharp.RuntimeBinder.CSharpCallPayload::.ctor(class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder,
    bool,
    bool,
    string,
    class [mscorlib]System.Type,
    class [mscorlib]System.Type[])
    IL_006b: call class [System.Core]System.Scripting.Actions.CallSite`1 class [System.Core]System.Scripting.Actions.CallSite`1>::Create(class [System.Core]System.Scripting.Actions.CallSiteBinder)
    IL_0070: stsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site2'
    IL_0075: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site2'
    IL_007a: ldfld      !0 class [System.Core]System.Scripting.Actions.CallSite`1>::Target
    IL_007f: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site2'
    IL_0084: ldloc.0
    IL_0085: callvirt instance void class [System.Core]System.Action`2::Invoke(!0,
                                                                                                                                                 !1)
    IL_008a: ret
    } // end of method Program::Main

    如果是var或Foo的话直接这样就完事了:

    Code
    1 IL_0000: newobj instance void LearnCSharp4.Foo::.ctor()
    2 IL_0005: stloc.0
    3 IL_0006: ldloc.0
    4 IL_0007: callvirt instance void LearnCSharp4.Foo::Do1()
    5 IL_000c: ldloc.0
    6 IL_000d: callvirt instance void LearnCSharp4.Foo::Do2()
    7 IL_0012: ret

    OK,看出不同来了。然后取消掉对foo.KissFanweixiao();的注释,再编译,再用ILDASM看,Do1()和KissFanWeixiao()的地位应该是一样的——因为dynamic与编译时无关嘛(好像是废话...但是这点很重要)。我们再看一眼有三个方法后的MSIL:

    Code
    1.method private hidebysig static void  Main(string[] args) cil managed
    2{
    3 .entrypoint
    4 // Code size       205 (0xcd)
    5 .maxstack 7
    6 .locals init ([0] object foo1)
    7 IL_0000: newobj instance void LearnCSharp4.Foo::.ctor()
    8 IL_0005: stloc.0
    9 IL_0006: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'

    o__SiteContainer0'::'<>p__Site1'
    10 IL_000b: brtrue.s   IL_0033
    11 IL_000d: call class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder::GetInstance()
    12 IL_0012: ldc.i4.0
    13 IL_0013: ldc.i4.0
    14 IL_0014: ldstr "Do1"
    15 IL_0019: ldtoken    [mscorlib]System.Object
    16 IL_001e: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    17 IL_0023: ldnull
    18 IL_0024: newobj instance void [System.Core]Microsoft.CSharp.RuntimeBinder.CSharpCallPayload::.ctor(class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder,
    19 bool,
    20 bool,
    21 string,
    22 class [mscorlib]System.Type,
    23 class [mscorlib]System.Type[])
    24 IL_0029: call class [System.Core]System.Scripting.Actions.CallSite`1 class [System.Core]System.Scripting.Actions.CallSite`1>::Create(class [System.Core]System.Scripting.Actions.CallSiteBinder)
    25 IL_002e: stsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site1'
    26 IL_0033: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site1'
    27 IL_0038: ldfld      !0 class [System.Core]System.Scripting.Actions.CallSite`1>::Target
    28 IL_003d: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site1'
    29 IL_0042: ldloc.0
    30 IL_0043: callvirt instance void class [System.Core]System.Action`2::Invoke(!0,
    31                                                                                                                                             !1)
    32 IL_0048: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site2'
    33 IL_004d: brtrue.s   IL_0075
    34 IL_004f: call class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder::GetInstance()
    35 IL_0054: ldc.i4.0
    36 IL_0055: ldc.i4.0
    37 IL_0056: ldstr "Do2"
    38 IL_005b: ldtoken    [mscorlib]System.Object
    39 IL_0060: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    40 IL_0065: ldnull
    41 IL_0066: newobj instance void [System.Core]Microsoft.CSharp.RuntimeBinder.CSharpCallPayload::.ctor(class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder,
    42 bool,
    43 bool,
    44 string,
    45 class [mscorlib]System.Type,
    46 class [mscorlib]System.Type[])
    47 IL_006b: call class [System.Core]System.Scripting.Actions.CallSite`1 class [System.Core]System.Scripting.Actions.CallSite`1>::Create(class [System.Core]System.Scripting.Actions.CallSiteBinder)
    48 IL_0070: stsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site2'
    49 IL_0075: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site2'
    50 IL_007a: ldfld      !0 class [System.Core]System.Scripting.Actions.CallSite`1>::Target
    51 IL_007f: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site2'
    52 IL_0084: ldloc.0
    53 IL_0085: callvirt instance void class [System.Core]System.Action`2::Invoke(!0,
    54                                                                                                                                             !1)
    55 IL_008a: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site3'
    56 IL_008f: brtrue.s   IL_00b7
    57 IL_0091: call class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder::GetInstance()
    58 IL_0096: ldc.i4.0
    59 IL_0097: ldc.i4.0
    60 IL_0098: ldstr "KissFanweixiao"
    61 IL_009d: ldtoken    [mscorlib]System.Object
    62 IL_00a2: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    63 IL_00a7: ldnull
    64 IL_00a8: newobj instance void [System.Core]Microsoft.CSharp.RuntimeBinder.CSharpCallPayload::.ctor(class [System.Core]Microsoft.CSharp.RuntimeBinder.RuntimeBinder,
    65 bool,
    66 bool,
    67 string,
    68 class [mscorlib]System.Type,
    69 class [mscorlib]System.Type[])
    70 IL_00ad: call class [System.Core]System.Scripting.Actions.CallSite`1 class [System.Core]System.Scripting.Actions.CallSite`1>::Create(class [System.Core]System.Scripting.Actions.CallSiteBinder)
    71 IL_00b2: stsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site3'
    72 IL_00b7: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site3'
    73 IL_00bc: ldfld      !0 class [System.Core]System.Scripting.Actions.CallSite`1>::Target
    74 IL_00c1: ldsfld class [System.Core]System.Scripting.Actions.CallSite`1> LearnCSharp4.Program/'
    o__SiteContainer0'::'<>p__Site3'
    75 IL_00c6: ldloc.0
    76 IL_00c7: callvirt instance void class [System.Core]System.Action`2::Invoke(!0,
    77                                                                                                                                             !1)
    78 IL_00cc: ret
    79} // end of method Program::Main

    如果不喜欢看MSIL的话可以这样看:

    Code
    1private static void Main(string[] args)
    2{
    3 object foo1 = new Foo();
    4 if (

    o__SiteContainer0.<>p__Site1 == null)
    5 {
    6
    o__SiteContainer0.<>p__Site1 = CallSite>.Create(new CSharpCallPayload(Microsoft.CSharp.RuntimeBinder.RuntimeBinder.GetInstance(), false, false, "Do1", typeof(object), null));
    7    }
    8
    o__SiteContainer0.<>p__Site1.Target(
    o__SiteContainer0.<>p__Site1, foo1);
    9 if (
    o__SiteContainer0.<>p__Site2 == null)
    10 {
    11
    o__SiteContainer0.<>p__Site2 = CallSite>.Create(new CSharpCallPayload(Microsoft.CSharp.RuntimeBinder.RuntimeBinder.GetInstance(), false, false, "Do2", typeof(object), null));
    12    }
    13
    o__SiteContainer0.<>p__Site2.Target(
    o__SiteContainer0.<>p__Site2, foo1);
    14 if (
    o__SiteContainer0.<>p__Site3 == null)
    15 {
    16
    o__SiteContainer0.<>p__Site3 = CallSite>.Create(new CSharpCallPayload(Microsoft.CSharp.RuntimeBinder.RuntimeBinder.GetInstance(), false, false, "KissFanweixiao", typeof(object), null));
    17    }
    18
    o__SiteContainer0.<>p__Site3.Target(
    o__SiteContainer0.<>p__Site3, foo1);
    19}

    本文旨在为不方便下载和使用vs2010虚拟机朋友帮个忙.

    (在后台编辑的时候报stack overflow的问题...无法提交...)

  • 打印这篇文章
  • 与本文主题相关的文章
  • 返回首页