装箱和拆箱

在使用这种多类型系统时如何有效的拓展和提高系统的性能?
西雅图的那帮家伙们提出了Box(装箱) and UnBox(拆箱) 的想法。简单的说。装箱就是将值类型(value type)转换为引用类型(reference type)的过程;反之,就是拆箱。
装箱:
static   void  Main( string [] args)
{
 
double dubBox = 77.77/// 定义一个值形变量 
 object objBox = dubBox; /// 将变量的值装箱到 一个引用型对象中 
 Console.WriteLine("The Value is '{0}' and The Boxed is {1}",dubBox,objBox.ToString());
}
第一行我们创建了一个double类型的变量(dubBox)。显然按规则,CTS规定double是原类型,所以dubBox自然就是值类型的变量;第二行其实作了三个工作,这个将在下面的MSIL代码中看的一清二楚。第一步取出dubBox的值,第二步将值类型转换引用类型,第三步传值给objBox。
MSIL代码如下:
.method   private   hidebysig  static  void   Main( string [] args)  cil   managed
{
  
.custom   instance   void  [mscorlib]System.STAThreadAttribute::.ctor() = (  01   00   00   00  ) 
  
//  代码大小       40 (0x28)
   .maxstack    3
  
.locals   init  ( float64  V_0,
           
object  V_1)
  
IL_0000:    ldc.r8       77.769999999999996
  
IL_0009:    stloc.0
  
IL_000a:    ldloc.0
  
IL_000b:    box         [mscorlib]System.Double
  
IL_0010:    stloc.1
  
IL_0011:    ldstr        " The Value is '{0}' and The Boxed is {1} "
  
IL_0016:    ldloc.0
  
IL_0017:    box         [mscorlib]System.Double
  
IL_001c:    ldloc.1
  
IL_001d:    callvirt     instance   string  [mscorlib]System.Object::ToString()
  
IL_0022:    call         void  [mscorlib]System.Console::WriteLine( string ,
                                                                
object ,
                                                                
object )
  
IL_0027:    ret
//  end of method Class1::Main

在MSIL中,第IL_0000 至 IL_0010 行是描述前面两行代码的。在这我着重描述一下当dubBox被装箱时所发生的故事:(1)划分堆栈内存,在堆栈上分配的内存 = dubBox的大小 + objBox及其结构所占用的空间;(2)dubBox的值(77.7699999999996)被复制到新近分配的堆栈中;(3)将分配给objBox的地址压栈,此时它指向一个object类型,即引用类型。

拆箱作为装箱的逆过程。首先,box的时候,我们不需要显式的类型转换,但是在unbox时就必须进行类型转换。这是因为引用类型的对象可以被转换为任何类型。(当然,这也是电脑和人脑一个差别的体现)类型转换不容回避的将会受到来自CTS管理中心的监控——其标准自然是依据规则。

   static   void  Main( string [] args)
  
{
   
double dubBox = 77.77
   
object objBox = dubBox; 
   
double dubUnBox = (double)objBox; /// 将引用型对象拆箱 ,并返回值
   Console.WriteLine("The Value is '{0}' and The UnBoxed is {1}",dubBox,dubUnBox);
  }
MSIL代码如下:
.method   private   hidebysig  static  void   Main( string [] args)  cil   managed
{
  
.custom   instance   void  [mscorlib]System.STAThreadAttribute::.ctor() = (  01   00   00   00  ) 
  
//  代码大小       48 (0x30)
   .maxstack    3
  
.locals   init  ([ 0 float64  dubBox,
           [
1 object  objBox,
           [
2 float64  dubUnBox)
  
IL_0000:    ldc.r8       77.769999999999996
  
IL_0009:    stloc.0
  
IL_000a:    ldloc.0
  
IL_000b:    box         [mscorlib]System.Double
  
IL_0010:    stloc.1
  
IL_0011:    ldloc.1
  
IL_0012:    unbox       [mscorlib]System.Double
  
IL_0017:    ldind.r8
  
IL_0018:    stloc.2
  
IL_0019:    ldstr        " The Value is '{0}' and The UnBoxed is {1} "
  
IL_001e:    ldloc.0
  
IL_001f:    box         [mscorlib]System.Double
  
IL_0024:    ldloc.2
  
IL_0025:    box         [mscorlib]System.Double
  
IL_002a:    call         void  [mscorlib]System.Console::WriteLine( string ,
                                                                
object ,
                                                                
object )
  
IL_002f:    ret
//  end of method Class1::Main

在MSIL中,第IL_0011 至 IL_0018 行是描述新行代码的。在此我着重描述一下objBox在拆箱时的遭遇:(1)环境须先判断堆栈上指向合法对象的地址,以及在对此对象向指定的类型进行转换时是否合法,如果不合法,就抛出异常;(2)当判断类型转换正确,就返回一个指向对象内的值的指针。

看来,装箱和拆箱也不过如此,刚把‘值’给装到‘箱’里去了,有费了更多的劲把它拆解了,结合代码和MSIL看出,在调用Console.WriteLine()的过程中又出现了两次box,是的,其实这就是“暗箱操作”! 因为Console.WriteLine方法有许多的重载版本,此处的版本是以两个String对象为参数,而具有object 类型的参数的重载是编译器找到的最接近的版本,所以,编译器为了求得与这个方法的原型一致,就必须对值类型的dubBox和dubUnBox分别进行装箱(转换成引用类型)。

  所以,为了避免由于无谓的隐式装箱所造成的性能损失,在执行这些多类型重载方法之前,最好先对值进行装箱。现在我们把上述地代码改进为:

   static   void  Main( string [] args)
  
{
   
double dubBox = 77.77
   
object objBox = dubBox; 
   
double dubUnBox = (double)objBox; 
   
object objUnBox = dubUnBox;
   Console.WriteLine(
"The Value is '{0}' and The UnBoxed is {1}",objBox,objUnBox);
  }
MSIL代码:
.method   private   hidebysig  static  void   Main( string [] args)  cil   managed
{
  
.custom   instance   void  [mscorlib]System.STAThreadAttribute::.ctor() = (  01   00   00   00  ) 
  
//  代码大小       45 (0x2d)
   .maxstack    3
  
.locals   init  ([ 0 float64  dubBox,
           [
1 object  objBox,
           [
2 float64  dubUnBox,
           [
3 object  objUnBox)
  
IL_0000:    ldc.r8       77.769999999999996
  
IL_0009:    stloc.0
  
IL_000a:    ldloc.0
  
IL_000b:    box         [mscorlib]System.Double
  
IL_0010:    stloc.1
  
IL_0011:    ldloc.1
  
IL_0012:    unbox       [mscorlib]System.Double
  
IL_0017:    ldind.r8
  
IL_0018:    stloc.2
  
IL_0019:    ldloc.2
  
IL_001a:    box         [mscorlib]System.Double
  
IL_001f:    stloc.3
  
IL_0020:    ldstr        " The Value is '{0}' and The UnBoxed is {1} "
  
IL_0025:    ldloc.1
  
IL_0026:    ldloc.3
  
IL_0027:    call         void  [mscorlib]System.Console::WriteLine( string ,
                                                                
object ,
                                                                
object )
  
IL_002c:    ret
//  end of method Class1::Main

你可能感兴趣的:(拆箱)