SAL

  博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

【转】全面认识装箱与折箱

Posted on 2010-11-23 14:47  SAL  阅读(332)  评论(0编辑  收藏  举报

首先说明:为什么要清楚装箱与折箱,因为装箱与折箱对程序的性能有很大的影响,因此在写代码的时候要时刻注意这些问题。

装箱与折箱都只对值类型数据而言,而对于引用类型数据,都是在托管的堆上运行的,也就不存在装箱与折箱问题了,也就不讨论了。

对于所有的基本数据类型,除了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代码,让你的程序新效率更高,请注意这个装箱与折箱问题吧。