登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

樱之花

叶散的时候,你明白欢聚;花谢的时候,你明白青春.

 
 
 

日志

 
 
关于我

分类中“我的实验室”是我在日常工作中的一些知识总结,有些写的比较匆忙,可能大家在阅读时会产生困扰,后期有时间我会重新整理编辑,谢谢大家的到访,您们的支持是我前进的动力!

C#中的装箱和拆箱  

2012-08-31 11:41:26|  分类: .NET/C# |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
在C#中,有两个类型:值类型和引用类型。值类型属于一种轻类型,它不像引用类型的变量会在托管堆上分配内存,不会被垃圾回收,它没有堆上的每个对象都有的额外成员(类型对象指针和同步块索引)。但是在现实生活中,我们还是要获取对值类型的一个实例的引用。

还是用那个经典的例子ArrayList。

这个ArrayList是Array的强化版,它不同于数组。数组要求每个索引的数据是同一类型的,而ArrayList则不然,它允许插入的数据类型不一致。

   1:  public virtual int Add(object value)
   2:  {
   3:      if (this._size == this._items.Length)
   4:      {
   5:          this.EnsureCapacity(this._size + 1);
   6:      }
   7:      this._items[this._size] = value;
   8:      this._version++;
   9:      return this._size++;
  10:  }

这个ArrayList中有一个方法Add,就是向ArrayList实例的尾部添加一个数据。这里最关键的是,这个添加的数据的类型是老大哥object,这也是为什么ArrayList可以添加各种数据类型的一个重要原因。

那么,当我们向ArrayList中添加一个int类型的数据时,是不是有

public virtual int Add(int value)

{
    ......
}

这样的重载方法呢?很不幸,并没有。

这也就是说明,当我们添加一个int类型数据时,实际上最终的IL代码是添加了object类型的数据。其实,这就是这次所讲的装箱操作。

装箱是指将值类型转换为引用类型,拆箱是指将引用类型转换为值类型。

值类型

在装箱操作中,内部发生了以下几件事:

Step1:在托管堆上分配内存

Step2:值类型的字段复制到新分配的堆内存

Step3:返回对象的地址

C#编译器会自动生成将一个值类型的实例装箱所需要的IL代码。

拆箱

乍一看,拆箱即是装箱的逆操作。其实,这就大错特错了,因为仔细观察拆箱的逆操作,就会发现里面有些步骤是不需要的。

在拆箱操作中,内部只发生了以下两件事:

Step1:获取被装箱完毕(boxed)值(现在叫做对象咯)的地址

Step2:将这个地址引用的值复制到基于栈的值类型实例中

将值类型的Step倒过来看,就会发现最本质的区别是拆箱操作不需要将值复制到内存中,因为值类型压根就不需要分配内存,它是直接存储在栈上。

综述

从上面的分析可以看出,无论是装箱和拆箱都会对应用程序的速度和内存消耗产生不利影响,这里面涉及到堆和栈的转换。所以在现实生活中,装箱和拆箱操作使用得谨慎。

像上文中的ArrayList.Add就是装箱的一个例子,在数据量较大的时候对性能的影响很明显的。

在一般的编码中,我们会用List<T>来替代。

ArrayList版本 
   1:  ArrayList arrayList=new ArrayList();

   2:  for(int i=0;i<50000;i++)
   3:  {
   4:      arrayList.Add(i);
   5:  }


List<T>版本
   1:  List<int> list = new List<int>();
   2:  for (int i = 0; i < 50000; i++)
   3:  {
   4:      list.Add(i);
   5:  }

后者避免了50000次的装箱操作,如果次数更大的时候,性能影响就更明显了。所以,就我而言,在现实中我基本没用过ArrayList,List<T>泛型类可以解决绝大部分事情,而且还有一些额外的优势,这个以后会说。


补充
CLR还允许将一个值类型拆箱为同一个值类型的可空版本。
   1:  Int32 x=5;
   2:  Int32 y=(Int32)x;
可空值类型int32?等价于Nullable<Int32>。

  评论这张
 
阅读(753)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018