装箱与拆箱的走走停停

上一篇简单述说了值类型与引用类型的关系,那么不能不说说值类型的拆箱与装箱:

      将值类型装箱就相当于把它包装起来给人看,"你瞧,我现在是引用类型了",顾名思义拆箱就是将包装卸下来"其实我是值类型"。

   在将值类型利用装箱机制打包成引用时他要进行许多的打扮:

      1.首先要给他一个空间(在托管堆中分配内存),多大呢,要必须要容得下包装所需要的物件化妆品之类的(各自段所需的内存量),此外还要有专家设计师吧(类型对象指针和同步块索引两个额外的成员);

      2.空间有了,他就要开始将自己的东西和物件搬过来(只读类型的字段复制到新分配的堆内存);

      3.一切准备就绪,不过此时出了意外,他被人顶替冒充了,而冒充它的那个人很清楚这个房间的位置(返回对象地址,该地址就是对象引用)。

上面解释可能会有点牵强,给个例子一目了然:

 1 struct Point{public int x,y;}
2 public sealed class Program{ 3 public static void Main() 4 { 5 ArrayList a = new ArrayList(); 6 Point p; 7 p.x=1;p.y=1; 8 a.Add(p); 9 } 10 }

最简单不过的代码了,由于Add()方法参数是Object类型,所以在执行时要进行一次装箱操作:Point值类型实例p中的字段会复制到新分配的Point对象中,已装箱的Point对象的地址返回并传给Add方法,需要说明的是Point对象此时是引用类型存在于堆中,Point值类型变量p可被重用,a已经不知道他的任何事情,由此可见已装箱值类型生存期超过了未装箱值类型的生存期。

-------------------------------------------------------------------------------

接下来说说拆箱:

  紧接上段代码,如若Point p = (Point)a[0];代码执行时,就进行了一次拆箱:

  一个人他知道了那个房间的地址,他把东西都要了回来,而东西可能已经变了(拆箱不是简单的装箱逆过程,它的代价比装箱要低,拆箱就是获取指针的过程,该指针指向包含在一个对象中的原始值类型(数据字段),指针指向的是已装箱实例中未装箱的部分,不要求在内存中复制任何字节);

  拆箱时要注意:1.包含"对已装箱类型实例的引用"的变量为null时,会抛出异常(他都没有房间,也没有物件,你找个P啊)

         2.如果引用的对象不是所需值类型的已装箱实例,抛出异常(张三的东西,李四来要,对方能给吗);

--------------------------------------------------------------------------------

下面来做个脑筋急转弯:

1 public static void Main(){
2         int v=5;
3         Object o = v;
4         v=123;
5         Console.WriteLine(v+","+(int)o);
6 }

问:上面代码发生了多少次装箱?想好在打开。。。

三次,一次很好理解,剩下的两次,对比Console.WriteLine参数即可理解
View Code

部分内容参考自《CLR C#》

   

原文地址:https://www.cnblogs.com/mjys-gh/p/4989718.html