Question

When we use dynamic type over object type

weather we can overcome Boxing/UnBoxing overhead ?

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

From both the method which one will be efficient and friendly to processor ?

Was it helpful?

Solution 2

There is likely no difference at all. From Microsoft:

Type dynamic behaves like type object in most circumstances. However, operations that contain expressions of type dynamic are not resolved or type checked by the compiler.

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

From this I infer that dynamic will act as an object until it is used in an expression. This includes parameter passing.

OTHER TIPS

In terms of boxing, it will make no difference. Take the following code:

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

    static void PrintDynamic(dynamic p)
    {

    }
}

If I decompile the method Test() in to IL I get:

.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
} 

You can see that despite the argument to Test being declared as dynamic, the integer is boxed.

EDIT

In response to your question about the discrepancy in timings, consider the following methods:

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

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

The IL for the first looks like this:

.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

For the second:

.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

This goes some way to explain why using dynamic initially takes longer. I suspect there is some caching mechanism going on, meaning that you don't get the performance hit after the first time.

If my memory serves my right:

The first time you use a dynamictype the compiler will generate a callsite that it will use for all consequential read of the variable, hence the slow first hit.

The extra time spent for each read after the initial is to do a lookup for the cached callsite and then performs the unboxing.

Do not hesitate to correct me or add to this answer in the comments!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top