CLR via C# 值类型的装箱和拆箱

值类型比引用类型“轻”,原因是它们不作为对象在托管堆中分配,不被垃圾回收,也不通过指针进行引用。

但很多时候都需要获取对值类型实例的引用。

创建ArrayList来容纳一组Point结构。

Add方法原型如下:

Add获取的是一个Object参数。也就是说,Add获取对托管堆上的一个对象的引用(或指针)来作为参数。

但是代码传递的是Point,值类型。为了使代码正确工作,Point值类型必须转换成真正的、在堆中托管的对象,而且必须获取对该对象的引用。

//--

将值类型转换成引用类型要使用装箱机制。下面总结了对值类型的实例进行装箱时所发生的事情:

1.在托管堆中分配内存。分配的内存量是值类型各字段所需的内存量,还要加上托管堆所有对象都有的两个额外成员(类型对象指针和同步块索引)所需的内存量。

2.值类型的字段复制到新分配的堆内存。

3.返回对象地址。现在该地址是对象的引用;值类型成了引用类型。

//--

C#编译器自动生成对值类型实例进行装箱所需的IL代码。

//--

泛型集合类,性能显著提升,不需要装箱/拆箱,托管堆中需要创建的对象减少了,降低垃圾回收次数,类型安全。

//--

拆箱

它获取ArrayList的元素0包含的引用(或指针),试图将其放到Point值类型的实例point中。

为此,已装箱的Point对象中的所有字段都必须复制到值类型变量point中,后者在线程栈上。CLR分两步完成复制。

第一步:获取已装箱Point对象中的各个Point字段的地址。这个过程称为拆箱(unboxing)

第二步:将字段包含的值从堆复制到基于栈的值类型实例中。

//--

拆箱不是直接装箱过程倒过来。拆箱的代价比装箱低得多。拆箱其实就是获取指针的过程,该指针指向包含在一个对象中的原始值类型(数据字段)。其实,指针指向的是已装箱实例中的未装箱部分。所以和装箱不同,拆箱不要求在内存中复制任何字节。直到这个重要区别之后,还应该知道的一个重点是,往往紧接着是拆箱发生一次字段复制。

//--

已装箱值类型实例在拆箱时,内部发生下面这些事情:

1.如果包含“对已装箱值类型实例的引用”的变量为null,抛出NullReferenceException异常。

2.如果引用的对象不是所需值类型的已装箱实例,抛出InvalidCastException异常。

拆箱时,只能转型为最初未装箱的值类型。

//--

大多数方法进行重载的唯一目的就是减少常用值类型的装箱次数。

//--

未装箱值类型比引用类型更“轻”。这要归结于以下两个原因:

1.不在托管堆上分配。

2.没有堆上的每个对象都有的额外成员:“类型对象指针”和“同步块索引”。

//--

使用接口更改已装箱值类型中的字段,在C#中,不用接口方法便无法做到。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值