装箱与拆箱

目录

  • 生活中的装箱与拆箱
  • C# 的装箱与拆箱
  • 值类型和引用类型
  • 装箱
  • 拆箱
  • 读者见解

生活中的装箱与拆箱

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

C# 的装箱与拆箱

  装箱:将值类型(如 int ,或自定义的值类型等)转换成 object 或者接口类型的一个过程。当 CLR 对值类型进行装箱时,会将该值包装为 System.Object 类型,再将包装后的对象存储在堆上。 拆箱就是从对象中提取对应的值类型的一个过程。

  装箱是隐式的;拆箱必定是显式的。

  与简单的赋值操作相比,装箱和拆箱都需要进行大量的数据计算。对值类型进行装箱时,CLR 必须重新分配一个新的对象。拆箱所需的强制转换也需要进行大量的计算,两者相比,仅仅是程度不高,并且也可能会出现类型转换发生的异常情形。如果你的操作正处于循环的中心,通过测试(如:Stopwatch),你会很明显的感觉到性能问题。

  .NET 2.0 引入的泛型其实在很大的程度上解决了装拆箱产生的类型转换问题,也减少了类型转换所引起的运行时的异常,及保证了类型安全,从而提高了性能。
        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,那在转换时也不用保证其运行时类型与要转换的类型一致。

「如果不想在世界上虚度一生,那就要学习一辈子。」-- 高尔基


【博主】反骨仔

【原文】http://www.cnblogs.com/liqingwen/p/6486332.html

【参考】微软官方文档 MSDN

C# 知识回顾 - 装箱与拆箱的更多相关文章

  1. [C#] C# 知识回顾 - 装箱与拆箱

    装箱与拆箱 目录 生活中的装箱与拆箱 C# 的装箱与拆箱 值类型和引用类型 装箱 拆箱 读者见解 生活中的装箱与拆箱    我们习惯了在网上购物,这次你想买本编程书 -- <C 语言从入门到放弃 ...

  2. java 基础知识七 装箱和拆箱

    java  基础知识七  装箱和拆箱 数据类型可分为两大种,基本数据类型(值类型)和类类型(引用数据类型) 装箱:把基本类型用他们相对应的引用类型包装起来,使他们可以具有对象的特质    基本数据类型 ...

  3. 有关c#装箱和拆箱知识整理

    c#装箱和拆箱知识,装箱和拆箱是一个抽象的概念. 1.装箱和拆箱是一个抽象的概念  2.装箱是将值类型转换为引用类型 : 拆箱是将引用类型转换为值类型 利用装箱和拆箱功能,可通过允许值类型的任何值与O ...

  4. C#基础知识系列二(值类型和引用类型、可空类型、堆和栈、装箱和拆箱)

    前言 之前对几个没什么理解,只是简单的用过可空类型,也是知道怎么用,至于为什么,还真不太清楚,通过整理本文章学到了很多知识,也许对于以后的各种代码优化都有好处. 本文的重点就是:值类型直接存储其值,引 ...

  5. C#基础回顾(二)—页面值传递、重载与重写、类与结构体、装箱与拆箱

    一.前言 -孤独的路上有梦想作伴,乘风破浪- 二.页面值传递 (1)C#各页面之间可以进行数据的交换和传递,页面之间可根据获取的数据,进行各自的操作(跳转.计算等操作).为了实现多种方式的数据传递,C ...

  6. 从别人那淘的知识 深入剖析Java中的装箱和拆箱

    (转载的海子的博文   海子:http://www.cnblogs.com/dolphin0520/) 深入剖析Java中的装箱和拆箱 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来 ...

  7. C#:装箱和拆箱相关知识整理

    1.装箱和拆箱是一个抽象的概念   2. 装箱是将值类型转换为引用类型 ;   拆箱是将引用类型转换为值类型   利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类型的值相互转换,将值类型 ...

  8. 【译】.NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱

    为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...

  9. .NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱 (转)

    作者: Edison Chou  来源: 博客园  发布时间: 2014-09-03 15:59  阅读: 318 次  推荐: 2   原文链接   [收藏]   原文作者:Shivprasad k ...

随机推荐

  1. KMP之我见

    第二次看kmp,才有点搞懂这个算法(我真是太弱了,就该orz陈老师和龙老师): kmp算法完成的任务是:给定两个字符串O和f,长度分别为n和m,判断f是否在O中出现,如果出现则返回出现的位置.常规方法 ...

  2. MindManager 安装注册

    正版现在998元,对于个人用户来说是不是太贵了.直接下载的还不能打开,挺奇怪.

  3. 013-Cookie状态保持

    常用的状态(信息)保持方式(重点) ViewState: ASP.NET 的 .aspx页面特有,页面级的: 就是在页面上的一个隐藏域中保存客户端单独使用的数据的一种方式: 服务器端控件的值都自动保存 ...

  4. Zepto.js-Ajax 请求

    Ajax 请求 执行Ajax请求.它可以是本地资源,或者通过支持HTTP access control的浏览器 或者通过 JSONP来实现跨域. 引入Ajax模块 <script src=&qu ...

  5. php session 生命周期代码实例

     php session 生命周期代码实例        我们为什么需要Session,就是因为我们需要存储各个用户的状态数据.那么试问,如果由你来设计解决这个需求的方案,那么也许你会设置这样一个数据 ...

  6. html标签默认样式整理

    引:http://www.jb51.net/web/94964.html 文为大家整理了html标签默认样式属性及浏览器默认样式等等,喜欢css布局的朋友们可以学下,希望对大家有所帮助 html, a ...

  7. java中Integer比较需要注意的问题

    java中Integer比较需要注意的问题 package com.srie.test; import java.util.HashMap; import java.util.Map; public ...

  8. 第一部分 记事本搞定第一个C#程序和编译过程剖析

    记事本搞定第一个C#程序 进行下面三个步骤:编码,编译和托管运行. 1.记事本进行编码: using System; class Program{ public static void Main() ...

  9. DNS没有生效的几个原因

    1.记录没有正确添加 请确认你的域名记录是否完全正确的添加.线路类型正确,记录类型正确 2.域名还没有生效 这个情况还会有另外一个现象,就是域名有时候可以ping,有时候不能ping. 这是因为你当地 ...

  10. CentOS7系统安装DNS服务

    CentOS7系统安装DNS服务 30.1.DNS是什么? DNS ( Domain Name System )是"域名系统"的英文缩写,简单来说就是一个数据库,用于存储网络中IP ...