valueType.ToString() 是否对 valueType 进行强制转换
本文关键字:valueType 转换 ToString 是否 | 更新日期: 2023-09-27 18:30:18
假设我在 C# 中有以下代码
int x = 0;
x.ToString();
这在内部是否是 X 的拳击?有没有办法从视觉工作室看到这种情况?
在这种特定情况下,您使用的是System.Int32
(int
)。这种类型重新定义了ToString
、Equals
和GetHashCode
,所以没有拳击。
如果您使用不重新定义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 方法指令。
如果要在调用值类型时避免装箱 Equals
、GetHashCode
和ToString
,则需要重写这些方法。