valueType.ToString() 是否对 valueType 进行强制转换

本文关键字:valueType 转换 ToString 是否 | 更新日期: 2023-09-27 18:30:18

假设我在 C# 中有以下代码

int x = 0;
x.ToString();

这在内部是否是 X 的拳击?有没有办法从视觉工作室看到这种情况?

valueType.ToString() 是否对 valueType 进行强制转换

在这种特定情况下,您使用的是System.Int32int)。这种类型重新定义了ToStringEqualsGetHashCode,所以没有拳击。

如果您使用不重新定义ToString struct您将拥有的是一个constrained callvirt System.Object.ToString()。约束的定义:

当调用virt方法指令以约束thisType为前缀时,该指令将按如下方式执行:

  • 如果 thisType 是一个值类型并且 thisType 实现了方法,则 ptr 作为调用方法指令的 'this' 指针未经修改地传递,以便通过 thisType 实现方法。
  • 如果 thisType 是一个值类型,并且 thisType 不实现方法,则 ptr 将被取消引用、装箱并作为 'this' 指针传递给 callvirt 方法指令。

因此,如果值类型实现ToString则没有装箱,如果它没有实现它,则有装箱......有趣。我不知道。

对于非虚拟方法(如 System.Object 中定义的GetType()),值类型始终装箱。刚刚测试了:

5.GetType();

生成的 IL 代码:

IL_0001: ldc.i4.5
IL_0002: box [mscorlib]System.Int32
IL_0007: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()

下面是代码生成的 IL:

IL_0001: LDC.i4.0   IL_0002: stloc.0//xIL_0003: ldloca.s 00//xIL_0005:调用 System.Int32.ToString

如您所见,没有拳击比赛。

另一方面,这段代码

object x = 0;
x.ToString();

不会奇怪地引起拳击:

IL_0001: LDC.i4.0   IL_0002:盒子系统.Int32IL_0007: stloc.0//xIL_0008: ldloc.0//xIL_0009: callvirt System.Object.ToString

通常,如果x的类型不是int而是任何值类型(struct),则必须覆盖ToString以避免装箱。具体而言,将发出受约束callvirt

  • 如果 thisType 是一个值类型并且 thisType 实现了方法,则 ptr 作为调用方法指令的 'this' 指针未经修改地传递,以便通过 thisType 实现方法。

  • 如果 thisType 是一个值类型,并且 thisType 不实现方法,则 ptr 将被取消引用、装箱并作为 'this' 指针传递给 callvirt 方法指令。

如果要在调用值类型时避免装箱 EqualsGetHashCodeToString,则需要重写这些方法。