众所周知,int有ToString()覆盖ToString()基类型方法的方法Object.
对于以下代码,
int x = 100;
object y = (object)x;
Console.Write(y.ToString());
Run Code Online (Sandbox Code Playgroud)
(1)谁叫ToString()?int还是对象?为什么?
(2)我们如何查看/查看真相?通过任何调试/工具?
由于该值已装箱,因此编译器知道的所有内容都是object,因此它是对 的常规虚拟调用object.ToString(),然后它将获取ToString()该结构的重写。所以:它是object.ToString()被调用的,并且Int32.ToString()覆盖是被执行的。
private static void Main()
{
int x = 100;
object y = (object)x;
Console.Write(y.ToString());
}
Run Code Online (Sandbox Code Playgroud)
变成(我的评论):
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] int32 x,
[1] object y)
// int x = 100;
L_0000: ldc.i4.s 100
L_0002: stloc.0
// object y = (object)x;
L_0003: ldloc.0
L_0004: box int32
L_0009: stloc.1
// Console.Write(y.ToString());
L_000a: ldloc.1
L_000b: callvirt instance string [mscorlib]System.Object::ToString()
L_0010: call void [mscorlib]System.Console::Write(string)
L_0015: ret
}
Run Code Online (Sandbox Code Playgroud)
重要的一行位于L_000b; 定期虚拟调用object.ToString().
更有趣的是非装箱值类型;如果已知值类型有 a ToString(),那么它可以发出静态调用:
private static void Main()
{
int x = 100;
Console.Write(x.ToString());
}
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] int32 x)
L_0000: ldc.i4.s 100
L_0002: stloc.0
L_0003: ldloca.s x
L_0005: call instance string [mscorlib]System.Int32::ToString()
L_000a: call void [mscorlib]System.Console::Write(string)
L_000f: ret
}
Run Code Online (Sandbox Code Playgroud)
请参阅 处的静态调用 ( call) L_0005。然而,在大多数值类型的情况下,它将使用约束调用,如果它被覆盖, JIT 将解释为静态调用,如果没有覆盖,则将解释为虚拟调用:
private static void Main()
{
var x = new KeyValuePair<int, string>(123, "abc");
Console.Write(x.ToString());
}
Run Code Online (Sandbox Code Playgroud)
变成:
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 3
.locals init (
[0] valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<int32, string> x)
L_0000: ldloca.s x
L_0002: ldc.i4.s 0x7b
L_0004: ldstr "abc"
L_0009: call instance void [mscorlib]System.Collections.Generic.KeyValuePair`2<int32, string>::.ctor(!0, !1)
L_000e: ldloca.s x
L_0010: constrained [mscorlib]System.Collections.Generic.KeyValuePair`2<int32, string>
L_0016: callvirt instance string [mscorlib]System.Object::ToString()
L_001b: call void [mscorlib]System.Console::Write(string)
L_0020: ret
}
Run Code Online (Sandbox Code Playgroud)
“constrained”/“callvirt”对 atL_0010和L_0016 一起构成了此构造,因此它实际上可能不是虚拟调用。JIT/运行时可以在上面做其他的事情。此处对此进行了更多讨论。
请注意,常规程序class将始终为此使用虚拟调用,但场景除外return base.ToString();,该场景是对基本类型实现的静态调用。
| 归档时间: |
|
| 查看次数: |
153 次 |
| 最近记录: |