在 C# 中将 Dynamic 和 var 转换为 Object
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17291273/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Casting Dynamic and var to Object in C#
提问by
Consider these functions:
考虑这些函数:
static void Take(object o)
{
Console.WriteLine("Received an object");
}
static void Take(int i)
{
Console.WriteLine("Received an integer");
}
When I call the Takefunction this way:
当我这样调用Take函数时:
var a = (object)2;
Take(a);
I get :Received an object
我得到:Received an object
But if call it like:
但如果这样称呼它:
dynamic b = (object) 2;
Take(b);
I get:Received an integer
我得到:Received an integer
Both parameters (a& b) are cast to object. But why compiler has this behavior?
两个参数 ( a& b) 都被强制转换为object. 但是为什么编译器有这种行为呢?
采纳答案by Ken Kin
varis just a syntactic sugar to let the type to be decided by the RHS.
var只是一个语法糖,让类型由RHS决定。
In your code:
在您的代码中:
var a = (object)2;
is equivalent to:
相当于:
object a = (object)2;
You get an object, since you boxed 2to an object.
你得到一个对象,因为你装箱2到一个对象。
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,您可能需要查看Using Type dynamic。请注意,该类型是静态类型,但动态类型的对象会绕过静态类型检查,即您指定的类型:
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.
我把完整的 IL(调试配置)放在我的答案后面。
For these two lines:
对于这两行:
var a=(object)2;
Take(a);
the IL are only:
IL 只有:
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_000fto IL_007aof TestMethod. It doesn't call the Take(object)or Take(int)directly, but invokes the method like this way:
从IL_000f到IL_007a的TestMethod。它不直接调用Take(object)or Take(int),而是像这样调用方法:
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:
的完整 IL 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[] CSdynamic b = (object) 2;
Take(b);
static void Take(int i)
{
Console.WriteLine("Received an integer");
}
00
)
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
回答by Siva Charan
dynamic:
动态的:
dynamicis aDynamically typed- Dynamically typed - This means the type of variable declared is decided by the compiler at run time.
dynamic是一个Dynamically typed- 动态类型 - 这意味着声明的变量类型由编译器在运行时决定。
var:
变量:
varis aStatically typed- Statically typed – This means the type of variable declared is decided by the compiler at compile time.
var是一个Statically typed- 静态类型 - 这意味着声明的变量类型由编译器在编译时决定。
By this, you see that Overload resolution occurs at run time for dynamic.
通过这种方式,您可以看到在运行时发生了重载解析dynamic。
So variable bholds as int
所以变量b保持为int
var a = (object)2;
Take(a);
That's the reason why Take(b);calls Take(int i)
这就是Take(b);打电话的原因Take(int i)
static void Take(object o)
{
Console.WriteLine("Received an object");
}
But in the case of var a = (object)2, variable aholds as 'object'
但在 的情况下var a = (object)2,变量a保持为“对象”
IL_000d: box [mscorlib]System.Int32
IL_0012: stloc.0
IL_0013: ldloc.0
IL_0014: call void ConsoleApp.Program::Take(object)
That's the reason why Take(a); calls Take(object o)
这就是为什么 Take(a); 电话Take(object o)
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);
回答by Guru Stron
In first case var means objectso Take(object o)is called. In second case you use dynamictype and despite that you've boxed your intit still has information about it's type -intso the best matching method is called.
在第一种情况下 var 意味着objectsoTake(object o)被调用。在第二种情况下,您使用dynamictype 并且尽管您已将其装箱,但int它仍然具有有关其类型的信息-int因此调用了最佳匹配方法。
回答by cuongle
If you take a look on C# specification:
如果您查看 C# 规范:
1.6.6.5 Method overloading
1.6.6.5 方法重载
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
7.5.4 动态重载解析的编译时检查
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, varis not dynamic, overload resolutionwill find overload method at compile-time.
所以,在你的第一种情况下,var不是动态的,重载解析会在编译时找到重载方法。
But in your second case, you are calling static method with dynamic arguments, overload resolutionwill find overload method at the run-time instead
但是在第二种情况下,您使用动态参数调用静态方法,重载解析将在运行时找到重载方法
回答by VS1
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
首先在该行放置一个断点:
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)2does not convert 2 to an object when assigned to a dynamic variable and b remains an int
这清楚地意味着代码:
dynamic b = (object)2当分配给动态变量时不会将 2 转换为对象并且 b 仍然是 int
Next, comment out your overload of
Take(int i)method and then put a break point on lineTake(b)(same: type ofbis stillint) but when you run it, you will see printed value is: Recieved object.Now, change your
dynamicvariable 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 anobject.
接下来,注释掉您的
Take(int i)方法重载,然后在行上放置一个断点Take(b)(相同:b仍然是 类型int)但是当您运行它时,您将看到打印的值为:已接收对象。现在,将您的
dynamic变量调用更改为以下代码:Take((object)b); //It now prints "Received an object"接下来,将您的调用更改为以下代码并查看返回的内容:
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目的.
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 .
这是因为:动态变量的最佳匹配类型是根据它在运行时保存的值来解析的,并且要调用的最佳匹配重载方法也是在运行时为动态变量解析的。
回答by YK1
The boxed integer argument resolution happens at compile time. Here is the IL:
装箱整数参数解析发生在编译时。这是IL:
##代码##You can see it is resolved to the objectoverload at compile time itself.
你可以看到它object在编译时被解析为重载本身。
When you use dynamic- the runtime binder comes into picture. dynamicnot 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.
当您使用时dynamic- 运行时绑定器会出现。dynamic不仅可以解析为托管 C# 对象,还可以解析为非托管对象,如 COM 对象或 JavaScript 对象,前提是这些对象存在运行时绑定器。
Instead of showing IL, I'll show decompiled code (easier to read):
我将显示反编译代码(更易于阅读),而不是显示 IL:
##代码##You see that Takemethod is resolved at runtime by the runtime binder and not by compiler. So, it will resolve it to the actual type.
您会看到该Take方法在运行时由运行时绑定器而不是编译器解析。因此,它会将其解析为实际类型。

