为整数类型调用 ToString 时是否涉及装箱
本文关键字:是否 整数 类型 调用 ToString | 更新日期: 2023-09-27 18:31:51
非常简单的问题:
int a = 5;
string str = a.ToString();
由于ToString
是 System.Object 的虚拟方法,这是否意味着每次我为整数类型调用此方法时,都会发生装箱?
你已经得到了答案,告诉你当值类型覆盖ToString()
时,当你调用它时不会有装箱,但很高兴有某种方式实际看到它。
取类型int?
(Nullable<int>
)。这是一个有用的类型,因为它是一个值类型,但装箱可能会产生空引用,并且不能通过空引用调用实例方法。它确实有一个重写的ToString()
方法。它没有(也不能有)重写的GetType()
方法。
int? i = null;
var s = i.ToString(); // okay: initialises s to ""
var t = i.GetType(); // not okay: throws NullReferenceException
这说明通话i.ToString()
中没有装箱,但通话i.GetType()
有装箱。
其他答案提到ToString
调用不会导致拳击。 值得注意的是一个推论:
int i = 42;
String.Format("number: {0}", i.ToString());
不会导致拳击,而:
int i = 42;
String.Format("number: {0}", i);
将。
(你听到了吗,雷利普?
(但是,请记住,如果您要将格式化程序应用于String.Format
(例如 CultureInfo
,需要使用第二个版本)
不,拳击不会发生。调用虚拟方法时,CLR 会查找类型对象指针,以从方法表中获取实际重写的方法。对于值类型,没有对象指针,因此进行直接非虚拟调用,JIT 知道没有多态副作用,因为值类型是密封的。但是,如果值类型的ToString()
调用 base.ToString()
:则可能会发生装箱,然后实际实例被装箱并传递给System.ValueType.ToString()
Int32.ToString()
不调用base.ToString()
并使用本机实现,因此不会发生拳击。
当你反编译Int32.ToString()
调用时,你可以看到它实现了FormatInt32
这是本机C++方法。该方法的实现方式如下:
public override string ToString()
{
return Number.FormatInt32(
this,
null,
NumberFormatInfo.CurrentInfo);
}
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern string FormatInt32(
int value,
string format,
NumberFormatInfo info);
哪个叫Int32ToDecChars
:
wchar_t* COMNumber::Int32ToDecChars(
wchar_t* p,
unsigned int value,
int digits)
{
LEAF_CONTRACT
_ASSERTE(p != NULL);
while (--digits >= 0 || value != 0) {
*--p = value % 10 + '0';
value /= 10;
}
return p;
}
它采用每个数字,转换为单独的char
并存储在字符串中。然后返回该字符串。所以不涉及int
的拳击。
在此链接下,您可以找到有关在int
上调用ToString()
时实际发生的情况的相当全面的解释。作为奖励,本文还解释了Int32.Parse()
背后的所有机制:
https://selvasamuel.wordpress.com/2008/03/14/boxingunboxing-in-net/
由于ToString
在Int32
类中被覆盖 - 不,在这种情况下不会有装箱,因为不会在object
上创建实例。
由于动态调度,调用了 Int32 的简单适当的方法。
这取决于 ToString() 函数在 Int32 类中的实现方式。由于 .net 框架完成了实现,我们无法确认是否会发生装箱。