C# 知识回顾 - 装箱与拆箱
装箱与拆箱
目录
- 生活中的装箱与拆箱
- C# 的装箱与拆箱
- 值类型和引用类型
- 装箱
- 拆箱
- 读者见解
生活中的装箱与拆箱
我们习惯了在网上购物,这次你想买本编程书 -- 《C 语言从入门到放弃》 ,下单成功后,卖家会帮你将这本入坑指南打好包装,我们可以称之为装箱;经过快递员的快马加鞭,风雨无阻,包裹就直接送到你手上了。你一定会以迅雷不及掩耳盗铃儿响叮当之势拆开包装,这个过程我们可以称之为拆箱,这时,入坑指南就顺利的送到你手上。

C# 的装箱与拆箱
装箱是隐式的;拆箱必定是显式的。
与简单的赋值操作相比,装箱和拆箱都需要进行大量的数据计算。对值类型进行装箱时,CLR 必须重新分配一个新的对象。拆箱所需的强制转换也需要进行大量的计算,两者相比,仅仅是程度不高,并且也可能会出现类型转换发生的异常情形。如果你的操作正处于循环的中心,通过测试(如:Stopwatch),你会很明显的感觉到性能问题。
static void Main(string[] args)
{
var i = ; //System.Int32 //对 i 装箱(隐式)
object obj = i; //对 obj 进行拆箱(显式)
i = (int)obj; Console.Read();
}
在这里,我先将变量 i (int 类型)进行了装箱,并分配给对象 obj。其次,再次将对象 obj 进行拆箱(即强转)并重新给变量 i(int 类型)赋值。

直接通过反编译得到的 IL 代码,从 box 和 unbox 这两个指令也可以看出具体在哪一步发生装箱和拆箱操作。
值类型和引用类型
值类型和引用类型,这两者本来没有多大的联系(可能就是基类为 object),设计人员通过一种名为装拆箱的操作使得这两种类型创建了新的联系,让任何值类型都可以当成对象(引用)类型来进行操作。
装拆箱其实就是值类型和引用类型两者之间的类型转换操作。这里,我简单梳理一下这两种类型:
(1)值类型:整型:Int;长整型:long;浮点型:float;字符型:char;布尔型:bool;枚举:enum;结构:struct;它们统一继承 System.ValueType。
(2)引用类型:数组,用户定义的类、接口、委托,object,字符串等。
(3)简单的堆栈图:

图:@ 表示一个引用地址
装箱
装箱就是值类型到 object 类型或者到该值类型所实现的接口类型所实现的一个隐式转换过程(可显式)。装箱的时候会在堆中自动创建一个对象实例,然后将该值复制到新对象内。
var i = ; //System.Int32
//对 i 装箱(隐式)进对象 o
object o = i;

从图可知,对象 o 存的是地址引用,指向的是堆上的值,这个值的类型和变量 i 一样,也是 int 类型,值(123)也就是从变量 i Copy 过来的一个副本值而已。
【备注】装箱默认是隐式的,当然,你可以选择显式,但这并不是必须的。
拆箱
拆箱是从 object 类型到值类型,或从接口类型到实现该接口的值类型的显式转换的一个过程。
拆箱:检查对象实例,确保它是给定值类型的一个装箱值后,再将该值从实例复制到值类型变量中。
int i = ; // 值类型
object o = i; // 装箱
int j = (int)o; // 拆箱

要在运行时成功拆箱值类型,被拆箱的项必须是对一个对象的引用,该对象是先前通过装箱该值类型的实例创建的。
拆箱时需要注意,转换出现异常的情形:

虽然,decimal 类型可以直接强转为 int 类型,但从调式的结果来看,拆箱时是会引发“转换无效”的异常。要记住,拆箱时强转的值类型,应以装箱时的值类型一致。
读者见解
深蓝医生:简单说,装箱就是把值类型变成引用类型使用;拆箱就是将引用类型变成值类型使用。然而,大量使用值类型会引起变量值的大量拷贝,反而降低运行效率。所以装箱没有那么可怕,这可以通过 EF的code first和SOD框架的code first代码进行测试(要有业务层代码这种),虽然SOD框架的实体类看起来都是“装箱”过的,但是它的性能不会输给EF。
lulianqi15:最后加的一句注意(decimal 类型可以直接强转为 int 类型........应以装箱时的值类型一致),其实不太严谨,decimal 128位,想想都不可能无缘无故转换成32位的数据,之所以能强制转换,是因为Decimal 自己实现了自定义强制转换public static explicit operator int(decimal value)。回到最后例子的报错,JIT肯定是知道obj是Decimal(因为Decimal数据移动到托管堆上后后还额外为其添加了类型对象指针及同步块索引,所以即使obj在ide里申明为object,不过jit是知道他就是Decimal)之所以发生异常的原因是CLR认为在生成il时就认为obj是object类型,而object没有实现explicit 指定重载(当然可以自己实现)。所以就调用了object默认的强制转换,检查类型指针的时候发现不合法就报错了,那如果认可Decimal可以强制转换为int,说到底最后在强制转换报错的根本原因也只是object没有实现explicit 指定重载。如果自定义类型自己实现了explicit,那在转换时也不用保证其运行时类型与要转换的类型一致。
C# 基础回顾系列
《C# 知识回顾 - 委托 delegate》、《C# 知识回顾 - 委托 delegate (续)》
《C# 知识回顾 - 事件入门》、《C# 知识回顾 - Event 事件》
《string 与 String,大 S 与小 S 之间没有什么不可言说的秘密》
《C# 知识回顾 - 你真的懂异常(Exception)吗?》
「如果不想在世界上虚度一生,那就要学习一辈子。」-- 高尔基
【博主】反骨仔
【原文】http://www.cnblogs.com/liqingwen/p/6486332.html
【参考】微软官方文档 MSDN
C# 知识回顾 - 装箱与拆箱的更多相关文章
- [C#] C# 知识回顾 - 装箱与拆箱
装箱与拆箱 目录 生活中的装箱与拆箱 C# 的装箱与拆箱 值类型和引用类型 装箱 拆箱 读者见解 生活中的装箱与拆箱 我们习惯了在网上购物,这次你想买本编程书 -- <C 语言从入门到放弃 ...
- java 基础知识七 装箱和拆箱
java 基础知识七 装箱和拆箱 数据类型可分为两大种,基本数据类型(值类型)和类类型(引用数据类型) 装箱:把基本类型用他们相对应的引用类型包装起来,使他们可以具有对象的特质 基本数据类型 ...
- 有关c#装箱和拆箱知识整理
c#装箱和拆箱知识,装箱和拆箱是一个抽象的概念. 1.装箱和拆箱是一个抽象的概念 2.装箱是将值类型转换为引用类型 : 拆箱是将引用类型转换为值类型 利用装箱和拆箱功能,可通过允许值类型的任何值与O ...
- C#基础知识系列二(值类型和引用类型、可空类型、堆和栈、装箱和拆箱)
前言 之前对几个没什么理解,只是简单的用过可空类型,也是知道怎么用,至于为什么,还真不太清楚,通过整理本文章学到了很多知识,也许对于以后的各种代码优化都有好处. 本文的重点就是:值类型直接存储其值,引 ...
- C#基础回顾(二)—页面值传递、重载与重写、类与结构体、装箱与拆箱
一.前言 -孤独的路上有梦想作伴,乘风破浪- 二.页面值传递 (1)C#各页面之间可以进行数据的交换和传递,页面之间可根据获取的数据,进行各自的操作(跳转.计算等操作).为了实现多种方式的数据传递,C ...
- 从别人那淘的知识 深入剖析Java中的装箱和拆箱
(转载的海子的博文 海子:http://www.cnblogs.com/dolphin0520/) 深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来 ...
- C#:装箱和拆箱相关知识整理
1.装箱和拆箱是一个抽象的概念 2. 装箱是将值类型转换为引用类型 ; 拆箱是将引用类型转换为值类型 利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类型的值相互转换,将值类型 ...
- 【译】.NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱
为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...
- .NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱 (转)
作者: Edison Chou 来源: 博客园 发布时间: 2014-09-03 15:59 阅读: 318 次 推荐: 2 原文链接 [收藏] 原文作者:Shivprasad k ...
随机推荐
- ipyparallel 中的 pi的求法
1.PI的求法的数学依据 如图,可以看见在边长为1的正方形里面,有一个1/4圆,我们随机在正方形中取点,点在圆内的概率和点在正方形内的概率之比正好为两者的面积之比.这样就有在圆内的点的数目比所有点的数 ...
- Java多线程(学习篇)
Java多线程:(学习篇) 1.什么是线程 2.线程状态 3.线程中断 4.线程交互 5.同步机制 6.锁机制 7.堵塞队列与堵塞栈 8.条件变量.原子量.线程池等 9.线性安全类和Callable与 ...
- JS前端的分享功能
给网页加上分享代码,借助网友的力量推广网站,目前已经很流行了 以下是网页代码 QQ空间分享代码如下: <a href="javascript:void(0);" onclic ...
- EM算法 大白话讲解
假设有一堆数据点,它是由两个线性模型产生的.公式如下: 模型参数为a,b,n:a为线性权值或斜率,b为常数偏置量,n为误差或者噪声. 一方面,假如我们被告知这两个模型的参数,则我们可以计算出损失. 对 ...
- Spring之循环依赖
转:http://my.oschina.net/tryUcatchUfinallyU/blog/287936 概述 如何检测循环依赖 循环依赖如何解决 Spring如何解决循环依赖 主要的几个缓存 主 ...
- Plugin execution not covered by lifecycle configuration的解决方案
pom配置文件中,提示错误:Plugin execution not covered by lifecycle configuration. 如图: 这表示m2e在其执行maven的生命周期管理时没有 ...
- MongoDB基础之六 索引
一 . 索引概述和基本操作 1. 索引提高查询速度,降低写入速度,权衡常用的查询字段,不必在太多列上建索引2. 在mongodb中,索引可以按字段升序/降序来创建,便于排序3. 默认是用btree来组 ...
- C++编程练习(15)----“排序算法 之 归并排序“
归并排序 归并排序(Merging Sort)的原理: 假设初始序列含有 n 个记录,则可以看成是 n 个有序的子序列,每个子序列的长度为1,然后两两归并,得到 [n/2] ([ x ] 表示不小于 ...
- 一次dns缓存引发的惨案
时间2015年的某个周六凌晨5点,公司官方的QQ群有用户反馈官网打不开了,但有的用户反馈可以打开,客服爬起来自己用电脑试了一下没有问题,就给客户反馈说,可能是自己网络的问题,请过会在试试.早点8点,越 ...
- 面向UI编程:ui.js 1.0 粗糙版本发布,分布式开发+容器化+组件化+配置化框架,从无到有的艰难创造
时隔第一次被UI思路激励,到现在1.0的粗糙版本发布,掐指一算整整半年了.半年之间,有些细节不断推翻重做,再推翻再重做.时隔今日,终于能先出来个东西了,这个版本很粗糙,主体功能大概能实现了,但是还是有 ...