我们先来看一个示例代码:

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ArrayList a = new ArrayList(); Point p; for (int i = ; i < ; i++)
{
p.x = p.y = i; a.Add(p);
} Console.ReadKey();
}
} struct Point
{
public Int32 x, y;
}
}

在本例中,ArrayList的Add方法原型如下:

public virtual Int32 Add(object value);

可以看来,Add方法需要获取一个Object类型参数,换言之,Add需要获取对托管堆上的一个对象的引用来作为参数。但在之前的代码中,传递的是值类型的参数。为了使代码能够工作,Point值类型必须转换成一个真正的、在堆中托管的对象。而且必须获取对这个对象的一个引用。

为了将一个值类型转换成一个引用类型,要使用一个名为"装箱"的机制。下面总结了对值类型的一个实例进行装箱时在内部发生的事情。

1)在托管堆中分配好内存。分配的内存量是值类型的各个字段所需要的内存量再加上托管堆的所有对象都有的两个额外成员需要的内存量。

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

3)返回对象的地址。

在知道装箱如何进行之后,接着谈谈拆箱。

Point p = (Point)a[0];

现在要获取ArrayList的元素0中包含的引用,并试图将其放到一个Point值类型的实例p中。为了做到这一点,包含在已装箱Point对象中的所有字段都必须复制到值类型变量p中,后者在线程栈上。CLR分两步完成这个复制操作。第一步是获取已装箱的Point对象中的各个Point字段的地址,这个过程称为拆箱。第二步是将这些字段包含的值复制到基于栈的值类型实例中。

 static void Main(string[] args)
{
Int32 x = 5; Object o = x; Int16 y = (Int16)o; //抛出一个InvalidCastException异常 Int16 y = (Int16)(Int32)o; //这个是正确的写法 Console.ReadKey();
}

从逻辑上讲,完全可以获取o所引用的一个已装箱的Int32,然后将其强制转换为一个Int16。然而,在对一个对象进行拆箱的时候,只能将其转型为原先未装箱时的值类型。 

由于未装箱的值类型没有同步块索引,所以不能使用System.Threading.Monitor类型的各种方法(或者使用C#的lock语句)让多个线程同步对这个实例的访问。

虽然未装箱的值类型没有类型对象指针,但仍可调用由类型继承或重写的虚方法(比如Equals、GetHashCode或者ToString)。用于调用虚方法的值类型不会被装箱。然而,如果你重写的虚方法要调用方法在基类中的实现,那么在调用基类的实现时,值类型实例就会装箱。然而,调用一个非虚的、继承的方法时(比如GetType或MemberwiseClone),无论如何都要对值类型进行装箱。这是因为这些方法是由System.Object定义的,所以这些方法期望this实参指向堆上一个对象的指针。除以之外,将值类型的一个未装箱实例转型为类型的某个接口时,要求对实例进行装箱。这是因为接口变量必须包含对堆上的一个对象的引用。

[CLR via C#]值类型的装箱和拆箱的更多相关文章

  1. [CLR via C#]5.3 值类型的装箱和拆箱

    原文:[CLR via C#]5.3 值类型的装箱和拆箱 在CLR中为了将一个值类型转换成一个引用类型,要使用一个名为装箱的机制. 下面总结了对值类型的一个实例进行装箱操作时内部发生的事: 1)在托管 ...

  2. 【.Net基础二】浅谈引用类型、值类型和装箱、拆箱

    目前在看CLR via C#,把总结的记下来,索性就把他写成一个系列吧. 1.[.Net基础一] 类型.对象.线程栈.托管堆运行时的相互关系 2.[.Net基础二]浅谈引用类型.值类型和装箱.拆箱 引 ...

  3. CLR via 笔记 5.3 值类型的装箱和拆箱

    1.装箱 为了将一个值类型转换成一个引用类型,要使用一个名为装箱(Boxing)的机制. 1.在托管堆中分配好内存.分配的内存量是值类型的各个字段需要的内存量加上托管堆的所有对象都有的两个额外成员(类 ...

  4. 【深入理解CLR】2:细谈值类型的装箱和拆箱

    装箱 总所周知,值类型是比引用类型更“轻型”的一种类型,因为它们不作为对象在托管堆中分配,不会被垃圾回收,也不通过指针来引用.但在许多情况下,都需要获取对值类型的一个实例的引用.例如,假定要创建一个A ...

  5. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_值类型的装箱和拆箱(二)

    [注意]:如果知道自己写的代码会造成编译器反复对一个值类型进行装箱,请改成用手动方式对值类型进行装箱. [好处]:代码会变得更小.更快. [例子]: using System; public seal ...

  6. [C#] 类型学习笔记一:CLR中的类型,装箱和拆箱

    在学习.NET的时候,因为一些疑问,让我打算把.NET的类型篇做一个总结.总结以三篇博文的形式呈现. 这篇博文,作为三篇博文的第一篇,主要探讨了.NET Framework中的基本类型,以及这些类型一 ...

  7. 浅谈.NET中的类型和装箱、拆箱原理

    谈到装箱拆箱,大概的意思就是值类型和引用类型的相互转换呗---值类型到引用类型叫装箱,反之则叫拆箱.这当然没有问题,可是你只知道这么多,那么建议你花点时间看看楼主这篇文章 1. .NET中的类型 为了 ...

  8. 从CLR角度来看值类型与引用类型

    前言 本文中大部分示例代码来自于<CLR via C# Edition3>,并在此之上加以总结和简化,文中只是重点介绍几个比较有共性的问题,对一些细节不会做过深入的讲解. 前几天一直忙着翻 ...

  9. 转 C# 装箱和拆箱[整理]

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

随机推荐

  1. URL和报文知识总结 ——1

    第一部分:浏览器生成的消息 关键词:URL的解析  HTTP请求的生成  DNS服务器 1.URL(网址)的构成: 对于一个网址的解析: https://i.cnblogs.com/index.htm ...

  2. Python学习笔记一:第一个Python程序,变量,字符编码与二进制,用户交互程序

    第一个python程序 Windows:设置环境变量,X:\pthonxxx,xxx是版本号 在命令提示符下 输入python,进入解释器 >>>print(“Hello World ...

  3. st link 连接问题ST LINK is not in the DFU mode plesse restart it

    原因:插上st link后做了一些操作才点击升级.如点击了连接stlink,如下图等: 解决办法: 1. 拔掉stlink 2. 插上stlink 3. 不要点其他的,直接点击ST-LINK-> ...

  4. Docker开篇之HelloWorld

    按照程序世界的惯例,我们应该以HelloWorld的程序为起点开始介绍.那么接下来我们就看看Docker的HelloWorld是如何运行的. 安装 Docker CE 由于我的系统是OSX,个人推荐使 ...

  5. chapter1

    任何语言的开篇,想要学下去肯定要搞环境啦,下面我们就开始. 安装Kali Linux 虚拟机 首先进入kali的官网https://www.kali.org/downloads/,因为是新手,因此建议 ...

  6. MongoDB入门---数据库&&&集合的基本操作

    MongoDB作为一种nosql的数据库,它自己本身的增伤改查还有数据库集合的创建和展示与一般的数据库较之是有一部分差别的.我们今天就来看一下MongoDB的一些基本操作.    首先呢,就是先来数据 ...

  7. 全国Uber优步司机奖励政策 (1月11日-1月17日)

    本周已经公开奖励整的城市有:北 京.成 都.重 庆.上 海.深 圳.长 沙.佛 山.广 州.苏 州.杭 州.南 京.宁 波.青 岛.天 津.西 安.武 汉.厦 门,可按CTRL+F,搜城市名快速查找. ...

  8. JavaScript---通过正则表达式验证表单输入

    验证输入的name只能是数字或字母或下划线 js <script type="text/javascript"> function submitOn(){ var f ...

  9. jQuery个人总结

    选择 1. end()的使用 $('div') .find('h3') .eq(2) .html('Hello') .end() //退回到选中所有的h3元素的那一步 .eq(0) //选中第一个h3 ...

  10. 手机蓝牙APP扫描设备的时候异常断开(未完成)

    1.手机蓝牙APP打开立马就出现异常,测试在公司有这个问题,在宿舍没这个问题,怀疑是公司设备太多,导致扫描空间不够,或者扫描到奇怪的设备.数组越界之类,明天用log看一下 2. 看样子出了一个erro ...