含义
- 装箱:就是把值类型转换为object类型或由此值类型实现的任何接口类型
- 拆箱:把装箱后的引用类型转换为值类型
装箱与拆箱就是值类型与引用类型的转换,是值类型和引用类型之间的桥梁。只有值类型才存在装箱和拆箱,装箱是隐式的,而拆箱是显示的。装箱与拆箱的过程包含了对堆上内存的操作,故会消耗性能,装箱需要比原数据更多的空间,因为它需要生成引用类型的标准配置:类型对象指针和同步块索引
过程
装箱
int i = 1;
object o = i;
具体过程
- 在堆内申请内存,内存大小为值类型的大小,再加上额外固定空间(类型对象指针和同步块索引)
- 将值类型的字段拷贝到新分配的内存中
- 返回新引用对象的内存地址(给栈上的引用)
装箱就是生成图中除了i = 1变量之外另外两块内存空间数据的过程
拆箱
拆箱就是把装箱后的引用类型转换为值类型的过程,但是拆箱不是一定成功的,所以存在出现异常的可能
具体过程
int b = (int)o;
- 检查是否为Null,否则抛出NullReferenceException异常,检查实例是否为给定值类型的装箱值,否则抛出InvalidCastException异常,最后获得对象各个成员的地址
- 创建一个新的int值类型对象b,并将第一步获得的值复制到b中
如何避免装箱与拆箱
C# 2通过引入泛型来解决了装箱与拆箱的问题,我们可以通过使用泛型集合来避免不必要的装箱和拆箱,例子如下:
很多地方会出现隐蔽的装箱操作,例如,当我们需要实现自定义的结构体判等时有如下代码
struct Rectangle
{
public override bool Equals(object obj)
{
...
}
}
我们发现,默认的签名为将两个比较对象转化为object,这便会引起装箱操作,解决办法是实现一个泛型IEquatable接口: