首先说明:为什么要清楚装箱与折箱,因为装箱与折箱对程序的性能有很大的影响,因此在写代码的时候要时刻注意这些问题。
装箱与折箱都只对值类型数据而言,而对于引用类型数据,都是在托管的堆上运行的,也就不存在装箱与折箱问题了,也就不讨论了。
对于所有的基本数据类型,除了string(String)以外,其它的都是值类型。
看这样的一个例子:
int m_num=4;
object m_obj=m_num;
Console.WriteLine(“{0}“,(int)m_obj);
一共进行了几次装箱与折箱?
答案是两次装箱与一次折箱!其中的一次装箱与一次折箱应该看的很明白,还有一次装箱是什么时候呢?
让我们来看看ILDasm.exe工具为我们银板的IL代码:
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 32 (0x20)
.maxstack 2
.locals init ([0] int32 m_num,
[1] object m_obj)
IL_0000: ldc.i4.4
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: box [mscorlib]System.Int32
IL_0008: stloc.1
IL_0009: ldstr "{0}"
IL_000e: ldloc.1
IL_000f: unbox [mscorlib]System.Int32
IL_0014: ldind.i4
IL_0015: box [mscorlib]System.Int32
IL_001a: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_001f: ret
} // end of method Sample::Main
看到了吗?清楚的两次box与一次unbox.而第二次box是在call void System.Console::WriteLine()之前发生的。
因为WriteLine(string,object),它要求第二个参数为object类型,所以把m_obj折箱后又被装箱。是为了满足参数的要求。
也就是说上面的代码改为:
Console.WriteLine(“{0}“,m_obj);
那么就只有一次装箱了。
那这样做呢?
Console.WriteLine(“{0}“,m_num);
显然这是会发生一次装箱的。因为m_num为值类型,而参数要求object类型。
这就是说,当我们调用一些函数的时候应该注意这些问题了。
时间关系,今天早上先只写这一点,有时间再讨论这个问题。
注意:装箱与折箱是IL里最影响性能的地方,所以要尽可能少的产生装箱与折箱的IL代码。
因为很多地方都是隐式的(像上面的第二次装箱,而且这只是一个简单的说明,可以想像,在大量的代码里,会有多少这样的装箱与折箱发生着),所以,要想写出好的IL代码,让你的程序新效率更高,请注意这个装箱与折箱问题吧。