首页 > 代码库 > 值类型的装箱和拆箱

值类型的装箱和拆箱

  值类型是比引用类型更“轻型”的一种类型,因为它们不作为对象在托管堆中分配,不会被来及回收,也不通过指针来引用。但在许多情况下,都需要获取对值类型的一个实例的引用。

  例如,假定要创建一个ArrayList对象(System.Collections命名空间中定义的一个类型)来容纳一组Point结构,那么代码可能想下面这样:

//声明一个值类型struct Point{    public  Int32 x,y;}public  sealed class Program{    public static void Main(){        ArrayList a = new ArrarList();        Point p;//分配一个Point(不在堆中分配)        for(Int32 i=0;i < 10;i++){            p.x = p.y = i;//初始化值类型中的成员            a.Add(p);//对值类型进行装箱,并将引用添加到ArrayList中        }        ...    }}

  每次循环迭代,都会初始化一个Point的值类型字段(x和y)。然后,这个Point会存储到ArrayList中。在本例中,Add方法的原型如下:

public virtual Int32 Add(Object value);

  可以看出,Add需要获取一个Object参数。换言之,Add需要获取托管堆上的一个对象引用(或指针)来作为参数。但在之前的代码中,传递的是p,也就是一个Point,是一个值类型。为了是代码真确工作,Point值类型必须转换成一个真正的、在堆中托管的对象,而且必须获取对这个对象的一个引用。

  为了将一个值类型转换成一个引用类型,要使用一个名为装箱的机制。下面总结了对值类型的一个实例进行装箱操作时在内部发生的事情。

  1. 在托管堆中分配好内存。分配的内存量是值类型的各个字段需要的内存量加上托管堆的所有对象都有的两个额外成员(类型对象指针和同步块索引)需要的内存量。
  2. 值类型的字段复制到新分配的堆内存。
  3. 返回对象的地址。现在,这个地址是一个对象的引用,值类型现在是一个引用类型。

  在上述代码中,C#编译器检查到时项一个需要引用类型的方法传递一个值类型,所以会自动生成代码对对象进行装箱。