Var type cannot be passed as a method argument and method cannot return object type. Var type work in the scope where it defined. Dynamic type can be passed as a method argument and method also can return dynamic type. Need to cast object variable to original type to use it and performing desired operations.
Nope - var just means you're letting the compiler infer the type from the expression used to assign a value to the variable. So if you have an expression like: var x = new Widget(); x will be of type Widget , not object .
You can create custom dynamic objects by using the classes in the System. Dynamic namespace. For example, you can create an ExpandoObject and specify the members of that object at run time. You can also create your own type that inherits the DynamicObject class.
Object is useful when we don't have more information about the data type. Dynamic is useful when we need to code using reflection or dynamic languages or with the COM objects and when getting result out of the LinQ queries.
var
is just a syntactic sugar to let the type to be decided by the RHS.
In your code:
var a = (object)2;
is equivalent to:
object a = (object)2;
You get an object, since you boxed 2
to an object.
For dynamic
, you might want to have a look at Using Type dynamic. Note that The type is a static type, but an object of type dynamic bypasses static type checking, that is, the type you specified of:
dynamic b = (object) 2;
is bypassed, and the real type of it is resolved at runtime.
For how it's resolved at runtime, I believe it's much more complicated than you can imagine ..
Say you have the following code:
public static class TestClass {
public static void Take(object o) {
Console.WriteLine("Received an object");
}
public static void Take(int i) {
Console.WriteLine("Received an integer");
}
public static void TestMethod() {
var a=(object)2;
Take(a);
dynamic b=(object)2;
Take(b);
}
}
and I put the full IL(of debug configuration) at the rear of my answer.
For these two lines:
var a=(object)2;
Take(a);
the IL are only:
IL_0001: ldc.i4.2
IL_0002: box [mscorlib]System.Int32
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: call void TestClass::Take(object)
But for these two:
dynamic b=(object)2;
Take(b);
are from IL_000f
to IL_007a
of TestMethod
. It doesn't call the Take(object)
or Take(int)
directly, but invokes the method like this way:
object b = 2;
if (TestClass.<TestMethod>o__SiteContainer0.<>p__Site1 == null)
{
TestClass.<TestMethod>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Take", null, typeof(TestClass), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.IsStaticType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
TestClass.<TestMethod>o__SiteContainer0.<>p__Site1.Target(TestClass.<TestMethod>o__SiteContainer0.<>p__Site1, typeof(TestClass), b);
The full IL of TestClass
:
.class public auto ansi abstract sealed beforefieldinit TestClass
extends [mscorlib]System.Object
{
// Nested Types
.class nested private auto ansi abstract sealed beforefieldinit '<TestMethod>o__SiteContainer0'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Fields
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> '<>p__Site1'
} // end of class <TestMethod>o__SiteContainer0
// Methods
.method public hidebysig static
void Take (
object o
) cil managed
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Received an object"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method TestClass::Take
.method public hidebysig static
void Take (
int32 i
) cil managed
{
// Method begins at RVA 0x205e
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Received an integer"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method TestClass::Take
.method public hidebysig static
void TestMethod () cil managed
{
// Method begins at RVA 0x206c
// Code size 129 (0x81)
.maxstack 8
.locals init (
[0] object a,
[1] object b,
[2] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000
)
IL_0000: nop
IL_0001: ldc.i4.2
IL_0002: box [mscorlib]System.Int32
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: call void TestClass::Take(object)
IL_000e: nop
IL_000f: ldc.i4.2
IL_0010: box [mscorlib]System.Int32
IL_0015: stloc.1
IL_0016: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> TestClass/'<TestMethod>o__SiteContainer0'::'<>p__Site1'
IL_001b: brtrue.s IL_0060
IL_001d: ldc.i4 256
IL_0022: ldstr "Take"
IL_0027: ldnull
IL_0028: ldtoken TestClass
IL_002d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0032: ldc.i4.2
IL_0033: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_0038: stloc.2
IL_0039: ldloc.2
IL_003a: ldc.i4.0
IL_003b: ldc.i4.s 33
IL_003d: ldnull
IL_003e: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
IL_0043: stelem.ref
IL_0044: ldloc.2
IL_0045: ldc.i4.1
IL_0046: ldc.i4.0
IL_0047: ldnull
IL_0048: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
IL_004d: stelem.ref
IL_004e: ldloc.2
IL_004f: 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_0054: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_0059: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> TestClass/'<TestMethod>o__SiteContainer0'::'<>p__Site1'
IL_005e: br.s IL_0060
IL_0060: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> TestClass/'<TestMethod>o__SiteContainer0'::'<>p__Site1'
IL_0065: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>>::Target
IL_006a: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> TestClass/'<TestMethod>o__SiteContainer0'::'<>p__Site1'
IL_006f: ldtoken TestClass
IL_0074: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0079: ldloc.1
IL_007a: callvirt instance void class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>::Invoke(!0, !1, !2)
IL_007f: nop
IL_0080: ret
} // end of method TestClass::TestMethod
} // end of class TestClass
dynamic
is a Dynamically typed
var
is a Statically typed
By this, you see that Overload resolution occurs at run time for dynamic
.
So variable b
holds as int
dynamic b = (object) 2;
Take(b);
That's the reason why Take(b);
calls Take(int i)
static void Take(int i)
{
Console.WriteLine("Received an integer");
}
But in the case of var a = (object)2
, variable a
holds as 'object'
var a = (object)2;
Take(a);
That's the reason why Take(a); calls Take(object o)
static void Take(object o)
{
Console.WriteLine("Received an object");
}
The boxed integer argument resolution happens at compile time. Here is the IL:
IL_000d: box [mscorlib]System.Int32
IL_0012: stloc.0
IL_0013: ldloc.0
IL_0014: call void ConsoleApp.Program::Take(object)
You can see it is resolved to the object
overload at compile time itself.
When you use dynamic
- the runtime binder comes into picture. dynamic
not only can resolve to managed C# objects, but also to non-managed objects like COM objects or JavaScript objects given a runtime binder exists for those objects.
Instead of showing IL, I'll show decompiled code (easier to read):
object obj3 = 2;
if (<Main>o__SiteContainer0.<>p__Site1 == null)
{
<Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Take", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
}
<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, typeof(Program), obj3);
You see that Take
method is resolved at runtime by the runtime binder and not by compiler. So, it will resolve it to the actual type.
If you take a look on C# specification:
1.6.6.5 Method overloading
Method overloading permits multiple methods in the same class to have the same name as long as they have unique signatures. When compiling an invocation of an overloaded method, the compiler uses overload resolution to determine the specific method to invoke.
And:
7.5.4 Compile-time checking of dynamic overload resolution
For most dynamically bound operations the set of possible candidates for resolution is unknown at compiletime. In certain cases, however the candidate set is known at compile-time:
Static method calls with dynamic arguments
Instance method calls where the receiver is not a dynamic expression
Indexer calls where the receiver is not a dynamic expression
Constructor calls with dynamic arguments
In these cases a limited compile-time check is performed for each candidate to see if any of them could possibly apply at run-time
So, in your first case, var
is not dynamic, overload resolution will find overload method at compile-time.
But in your second case, you are calling static method with dynamic arguments, overload resolution will find overload method at the run-time instead
To help understand type resolution in your case for dynamic variables.
First put a break point at the line:
Take(b); //See here the type of b when u hover mouse over it, will be int
which clearly means that the code:
dynamic b = (object)2
does not convert 2 to an object when assigned to a dynamic variable and b remains an int
Next, comment out your overload of Take(int i)
method and
then put a break point on line Take(b)
(same: type of b
is still
int
) but when you run it, you will see printed value is: Recieved
object.
Now, change your dynamic
variable call to below code:
Take((object)b); //It now prints "Received an object"
Next, change your call to below code and see what is returned:
dynamic b = (long)2;
Take(b); // It now prints Received an object because there is no method overload that accepts a long and best matching overload is one that accepts an
object.
This is because: best matching type is resolved for the dynamic variables according to the value it holds at runtime and also best matching overload method to be called is resolved at runtime for dynamic variables .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With