2013-10-18 68 views
1

當我們使用動態類型超過對象類型編程C#中的「動態」類型

天氣我們可以克服拳擊/解鎖的開銷?

void Print(dynamic p) 
{ 
    Console.WriteLine(string.Format("{0} : {1}", p.GetType(),p)); 
} 

void Print(object p) 
{ 
    Console.WriteLine(string.Format("{0} : {1}", p.GetType(),p)); 
} 

從哪一種方法對處理器來說效率和友好?

+1

a)您是否親自測量過? b)你是預先優化(你不應該)還是隻是好奇? c)從不(很少)使用動態關鍵字 - 有龍。 – Gusdor

+1

d)給一個有意義的標題。 – 2013-10-18 10:56:39

+0

是的,我已經證實,但對於拳擊/ UnBoxing它需要0/1毫秒,但對於動態,它需要第一次大約39毫秒和下一個連續2毫秒.. :( – dinesh

回答

0

根本沒有差別。來自Microsoft:

在大多數情況下,動態類型的行爲類似於類型對象。但是,包含動態類型表達式的 操作不解決 或由編譯器檢查的類型。

http://msdn.microsoft.com/en-us/library/vstudio/dd264741.aspx

從這我推斷,直至在表達式中使用的動態將作爲一個對象。這包括參數傳遞。

2

在拳擊方面,它沒有什麼區別。看看下面的代碼:

public class TestClass 
{ 
    static void Test() 
    { 
     int v = 5; // Create an unboxed value type variable 
     PrintDynamic(v); 
    } 

    static void PrintDynamic(dynamic p) 
    { 

    } 
} 

如果我反編譯的方法Test()中IL我得到:

.method private hidebysig static void Test() cil managed 
{ 
    // Code size  16 (0x10) 
    .maxstack 1 
    .locals init ([0] int32 v) 
    IL_0000: nop 
    IL_0001: ldc.i4.5 
    IL_0002: stloc.0 
    IL_0003: ldloc.0 
    IL_0004: box  [mscorlib]System.Int32 
    IL_0009: call  void ConsoleApplication6.Session::PrintDynamic(object) 
    IL_000e: nop 
    IL_000f: ret 
} 

你可以看到,儘管參數Test被宣佈爲dynamic,取整數,裝箱。

編輯

在回答你關於在時序的差異問題,請考慮以下方法:

static void Print(object p) 
    { 
     string.Format("{0}", p); 
    } 

    static void PrintDynamic(dynamic p) 
    { 
     string.Format("{0}", p); 
    } 

的IL第一個看起來像這樣:

.method private hidebysig static void Print(object p) cil managed 
{ 
    // Code size  14 (0xe) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ldstr  "{0}" 
    IL_0006: ldarg.0 
    IL_0007: call  string [mscorlib]System.String::Format(string, 
                   object) 
    IL_000c: pop 
    IL_000d: ret 
} // end of method TestClass::Print 

第二種:

.method private hidebysig static void PrintDynamic(object p) cil managed 
{ 
    .param [1] 
    .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = (01 00 00 00) 
    // Code size  123 (0x7b) 
    .maxstack 8 
    .locals init ([0] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000) 
    IL_0000: nop 
    IL_0001: ldsfld  class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object>> ConsoleApplication6.TestClass/'<PrintDynamic>o__SiteContainer0'::'<>p__Site1' 
    IL_0006: brtrue.s IL_0055 
    IL_0008: ldc.i4  0x100 
    IL_000d: ldstr  "Format" 
    IL_0012: ldnull 
    IL_0013: ldtoken ConsoleApplication6.TestClass 
    IL_0018: call  class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) 
    IL_001d: ldc.i4.3 
    IL_001e: newarr  [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo 
    IL_0023: stloc.0 
    IL_0024: ldloc.0 
    IL_0025: ldc.i4.0 
    IL_0026: ldc.i4.s 33 
    IL_0028: ldnull 
    IL_0029: call  class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, 
                                              string) 
    IL_002e: stelem.ref 
    IL_002f: ldloc.0 
    IL_0030: ldc.i4.1 
    IL_0031: ldc.i4.3 
    IL_0032: ldnull 
    IL_0033: call  class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, 
                                              string) 
    IL_0038: stelem.ref 
    IL_0039: ldloc.0 
    IL_003a: ldc.i4.2 
    IL_003b: ldc.i4.0 
    IL_003c: ldnull 
    IL_003d: call  class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, 
                                              string) 
    IL_0042: stelem.ref 
    IL_0043: ldloc.0 
    IL_0044: call  class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, 
                                           string, 
                                           class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, 
                                           class [mscorlib]System.Type, 
                                           class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>) 
    IL_0049: call  class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) 
    IL_004e: stsfld  class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object>> ConsoleApplication6.TestClass/'<PrintDynamic>o__SiteContainer0'::'<>p__Site1' 
    IL_0053: br.s  IL_0055 
    IL_0055: ldsfld  class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object>> ConsoleApplication6.TestClass/'<PrintDynamic>o__SiteContainer0'::'<>p__Site1' 
    IL_005a: ldfld  !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object>>::Target 
    IL_005f: ldsfld  class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object>> ConsoleApplication6.TestClass/'<PrintDynamic>o__SiteContainer0'::'<>p__Site1' 
    IL_0064: ldtoken [mscorlib]System.String 
    IL_0069: call  class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) 
    IL_006e: ldstr  "{0}" 
    IL_0073: ldarg.0 
    IL_0074: callvirt instance void class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite,class [mscorlib]System.Type,string,object>::Invoke(!0, 
                                                !1, 
                                                !2, 
                                                !3) 
    IL_0079: nop 
    IL_007a: ret 
} // end of method TestClass::PrintDynamic 

這有些方法可以解釋爲什麼最初使用dynamic需要更長的時間。我懷疑有一些緩存機制正在進行,這意味着第一次之後你不會獲得性能。

+0

但我已經證實,但拳擊/ UnBoxing它需要0/1毫秒,但對於動態,它花了第一次大約39毫秒和下一個連續2毫秒,所以它不是同一儀式? – dinesh

0

如果我沒有記錯我的權利:

您使用dynamictype編譯器會生成,它將使用的變量的所有後果讀取,因此慢先打一個調用點的第一次。

初始化後每次讀取所花費的額外時間是對緩存的調用點進行查找,然後執行拆箱。

不要猶豫,糾正我或添加到評論中的這個答案!