为整数类型调用 ToString 时是否涉及装箱

本文关键字:是否 整数 类型 调用 ToString | 更新日期: 2023-09-27 18:31:51

非常简单的问题:

int a = 5;
string str = a.ToString();

由于ToString是 System.Object 的虚拟方法,这是否意味着每次我为整数类型调用此方法时,都会发生装箱?

为整数类型调用 ToString 时是否涉及装箱

你已经得到了答案,告诉你当值类型覆盖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/

由于ToStringInt32类中被覆盖 - 不,在这种情况下不会有装箱,因为不会在object上创建实例。

由于动态调度,调用了 Int32 的简单适当的方法。

这取决于 ToString() 函数在 Int32 类中的实现方式。由于 .net 框架完成了实现,我们无法确认是否会发生装箱。