Effective C#原则17:装箱和拆箱的最小化2010-12-09 博客园 Wu.Country@侠缘译值类型是数据的容器,它们不具备多太性。另一方面就是说,.Net框架被设 计成单一继承的引用类型,System.Object,在整个继承关系中做为根对象存在 。设计这两种类型的目的是截然不同的,.Net框架使用了装箱与拆箱来链接两种 不同类型的数据。装箱是把一个值类型数据放置在一个无类型的引用对象上,从 而使一个值类型在须要时可以当成引用类型来使用。拆箱则是额外的从“ 箱”上拷贝一份值类型数据。装箱和拆箱可以让你在须要使用 System.Object对象的地方使用值类型数据。但装箱与拆箱操作却是性能的强盗 ,在些时候装箱与拆箱会产生一些临时对象,它会导致程序存在一些隐藏的BUG 。应该尽可能的避免使用装箱与拆箱。装箱可以把一个值类型数据转化 也一个引用类型,一个新的引用对象在堆上创建,它就是这个“箱子 ”,值类型的数据就在这个引用类型中存储了一份拷贝。参见图2.3,演示 了装箱的对象是如何访问和存储的。箱子中包含一份这个值类型对象的拷贝,并 且复制实现了已经装箱对象的接口。当你想从这个箱子中取回任何内容时,一个 值类型数据的拷贝会被创建并返回。这就是装箱与拆箱的关键性概念:对象的一 个拷贝存放到箱子中,而不管何时你再访问这个箱子时,另一个拷贝又会被创建 。

图2.3,值类型数据在箱子中。把一个值类型数据转化成一个 System.Object的引用,一个无名的引用类型会被创建。值类型的数据就存储在 这个无名的引用对象中,所有的访问方法都要通过这个箱子才能到达值类型数据 存储的地方。最阴险的地方是这个装箱与拆箱很多时候是自动完成的!当 你在任何一个期望类型是System.Object的地方使用值类型数据时,编译器会生 成装箱与拆箱的语句。另外,当你通过一个接口指针来访问值类型数据时,装箱 与拆箱也会发生。当你装箱时不会得到任何警告,即使是最简单的语句也一样。 例如下面这个:
Console.WriteLine("A few numbers:{0}, {1}, {2}",
25, 32, 50);
使用重载的 Console.WriteLine函数须要一个System.Object类型的数组引用,整型是值类型 ,所以必须装箱后才能传给重载的WriteLine方法。唯一可以强制这三个整数成 为System.Object对象的方法就是把它们装箱。另外,在WriteLine内部,通过调 用箱子对象上的ToString()方法来到达箱子内部。某种意义上讲,你生成了这样 的结构:
int i =25;
object o = i; // box
Console.WriteLine(o.ToString());
在WriteLine内部,下面 的执行了下面的代码:
object o;
int i = ( int )o; // unbox
string output = i.ToString( );