十六:值类型的装箱和拆箱(二)

看以下代码:

public static void Main()

    {

        Int32 v = 5;    //创建一个未装箱的值类型变量

        Object o = v;   //o引用一个已装箱的Int32,包含值5

        v = 123;        //将未装箱的值修改成123

        Console.WriteLine(v + "," + (Int32)o);

}

以上代码发生了几次装箱,答案是3次。

首先在堆栈上创建一个Int32未装箱值类型的实例(v),并将其初始化为5,然后,创建一个Object类型的变量(o),并初始化它,让它指向v。但是,由于引用类型的变量必须指向堆中的对象,所以C#编译器会自动生成IL代码对v进行装箱,再将v的已装箱地址存储到o中。现在值123要放到未装箱的值类型实例v中,但这这个操作不会影响已装箱的Int32。

接着要调用WriteLine方法,该方法要求向其传递一个String对象,当前只有三个数据项:一个未装箱的Int32值类型实例(v)、一个String(它是一个引用类型),已及一个已装箱的Int32值类型的实例的引用(o),它要转换成一个未装箱的Int32,必须采用某种方式对这些数据项进行合并,以创建一个String。

C#编译器会生成代码来调用String对象的静态方法Concat,该方法有几个重载的版本,所有的版本执行的操作都一样,只是参数数量不一样,根据上面情况,选用的是Concat的以下版本:(注:在VS中把光标放到String上,单击右键,转到定义即可看到该类型的定义)

public static string Concat(object arg0, object arg1, object arg2);

为第一个参数arg0传递的是v,但是v是一个未装箱的值参数,而arg0是一个Object,所以必须对v进行装箱,并将v的地址传给arg0。为arg1参数传递的是字符串“,”,它是对一个String对象的引用,最后,arg2参数o会拆箱转型为一个Int32,从而获得包含在已装箱的Int32中的未装箱的Int32的地址,这个未装箱的Int32必须再次装箱,并将新的已装箱的实例的内存地址传给Concat的arg2参数。

Concat方法调用指定的每个对象的ToString方法,并连接每个对象的字符串表示。从Concat传回的String对象随即传给WriteLine方法,显示最终结果。 如果以上代码写成这样效率会更高些:

Console.WriteLine(v + "," + o);

移除了o前面的一个拆箱操作,之所以这样是因为o已经是一个Object引用类型,它的地址可以直接传给Concat方法,所以这样就少了一个拆箱和一个装箱的操作,提高了性能。

还可以这样写:

Console.WriteLine(v.ToString() + "," + o);

在未装箱的值类型实例v上调用ToString()方法,返回一个String,String对象是引用类型,能直接传给Concat方法,不需要任何装箱操作。

再看以下代码:

public static void Main()

       {

        Int32 v = 5;    //创建一个未装箱的值类型变量

        Object o = v;   //o引用一个已装箱的Int32,包含值5

        v = 123;        //将未装箱的值修改成123

        Console.WriteLine(v);//显示123

        v = (Int32)o;   //拆箱并将o复制到v

        Console.WriteLine(v);//显示5

 }

上面代码只发生了一次装箱,因为Console.WriteLine()方法有一个重载版本只接受一个Int32值作为参数:

public static void WriteLine(Int32 value);

假如知道自己写的代码会进行反复对一个值类型进行装箱,那么手动方式对值类型装箱会有更好的效果,如下:

public static void Main()

      {

        Int32 v = 5;    //创建一个未装箱的值类型变量

        //编译这一行是,v会被装箱三次

        Console.WriteLine("{0},{1},{2}", v, v, v);

        //下面v只被装箱一次

        Object o = v;

        Console.WriteLine("{0},{1},{2}", o, o, o);

}

  

 

 

posted @ 2009-01-28 23:46  Done  阅读(459)  评论(1编辑  收藏  举报