非常简单的问题:
int a = 5;
string str = a.ToString();
由于ToString
是System.Object的虚方法,这是否意味着每当我为整数类型调用此方法时,都会发生装箱?
答案 0 :(得分:12)
你已经得到了答案,告诉你当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()
中有拳击。
答案 1 :(得分:3)
不,拳击不会发生。调用虚方法时,CLR查找类型对象指针以从方法表中获取实际的重写方法。对于值类型,没有对象指针,因此直接进行非虚拟调用,JIT知道没有polimorphic副作用,因为值类型是密封的。但是,如果ToString()
值类型调用base.ToString()
,则可能会发生装箱:然后将实际实例装箱并传递给System.ValueType.ToString()
Int32.ToString()
不会调用base.ToString()
并使用本机实现,因此不会发生装箱。
答案 2 :(得分:3)
其他答案提到ToString
调用不会导致拳击。它无关紧要:
int i = 42;
String.Format("number: {0}", i.ToString());
不会导致拳击,而:
int i = 42;
String.Format("number: {0}", i);
意愿。
(你听说过,Resharper?)
(但请注意,如果您将格式化程序应用于String.Format
(例如CultureInfo
,则需要使用第二个版本)
答案 3 :(得分:2)
当您对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
拳击。
在此链接下,您可以找到在ToString()
上调用int
时实际发生的事情的相当详尽的说明。作为奖励,本文还解释了Int32.Parse()
背后的所有机制:
https://selvasamuel.wordpress.com/2008/03/14/boxingunboxing-in-net/
答案 4 :(得分:1)
由于在ToString
类中覆盖Int32
- 否,在这种情况下不会有装箱,因为object
上不会创建任何实例。
由于动态调度,调用Int32的简单方法。
答案 5 :(得分:-5)
这取决于在Int32类中如何实现ToString()函数。自.net框架实现以来,我们无法确认拳击是否发生。