1

当我们使用动态类型而不是对象类型时

天气我们可以克服装箱/拆箱开销吗?

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

从这两种方法中,哪一种对处理器高效且友好?

4

3 回答 3

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最初使用需要更长的时间。我怀疑存在一些缓存机制,这意味着您在第一次之后不会受到性能影响。

于 2013-10-18T11:14:39.323 回答
0

可能根本没有区别。来自微软:

在大多数情况下,动态类型的行为类似于类型对象。但是,包含动态类型表达式的操作不会被编译器解析或类型检查。

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

由此我推断,动态将作为一个对象,直到它被用于表达式中。这包括参数传递。

于 2013-10-18T10:52:42.067 回答
0

如果我没记错的话:

第一次使用动态类型时,编译器将生成一个调用站点,它将用于变量的所有后续读取,因此第一次命中很慢。

初始后每次读取所花费的额外时间是查找缓存的调用站点,然后执行拆箱。

不要犹豫,纠正我或在评论中添加这个答案!

于 2017-05-29T01:36:23.767 回答