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

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. python函数的四种参数传递方式

    python中函数传递参数有四种形式 fun1(a,b,c) fun2(a=1,b=2,c=3) fun3(*args) fun4(**kargs) 四种中最常见是前两种,基本上一般点的教程都会涉及, ...

  2. 【8086汇编-Day5】第三次实验

    练习一 结果展示: 这个程序执行下来貌似打印了数字36,但其实是两个数字3.6: 这段就是用来打印3:首先ah里放2,跟后面的int 21h结合起来就是调用21号中断例程的2号子程序,用来打印到标准输 ...

  3. Android Studio 引入 Git 并提交代码

    File -> Settings -> Version Control -> Git -> Path to Git executable -> 选择本地 Git 可执行文 ...

  4. 【POJ2482】Stars in Your Window

    [POJ2482]Stars in Your Window 题面 vjudge 题解 第一眼还真没发现这题居然™是个扫描线 令点的坐标为\((x,y)\)权值为\(c\),则 若这个点能对结果有\(c ...

  5. Docker - 容器中的tomcat如何使用startup.sh启动

    网上大多介绍的catalina.sh启动,因为docker容器中,无法直接启动startup.sh. 解决方法: 编辑catalina.sh,找到 >> "$CATALINA_O ...

  6. pg 与 oracle 比较

    所谓动态引擎,就是说比如有很多张表的Join,原始的做法是一开始就生成好这个执行计划,随后执行,但实际上很多表Join的时候,你一开始生成的那个执行计划很有可能是不对的. 那么动态执行计划就是指它可以 ...

  7. 两个有序数组合并成一个有序数组(要求时间复杂度为O(n))

    面试题: 怎样把两个有序数组合并成有序数组呢 逻辑步骤: 1.假设两个数组为A和B 2.A和B都是从小到大的顺序进行排列 ** 1.我们可以直接比较两个数组的首元素,哪个小就把这个小元素放入可变数组. ...

  8. vim程序员加强功能

    1.折叠      1.1折叠的方式有六种           manual:以标准的vim结构定义折叠跨越的范围,类似移动命令           indent:折叠与折叠的层次,对应于文本的缩排与 ...

  9. centos7下安装mysql8.0.12及设置权限

    一.mysql版本介绍 mysql的官网为:https://www.mysql.com/ 在官网上可以看到多个版本,主要版本如下, 1.MySQL Community Server 社区版本,开源免费 ...

  10. 『Golang』Go简介以及环境搭建

    简介 go语言是由Google进行维护的一个编程语言,发布自2009年.其以良好的编程风格.优秀的并发机制被广大的技术人员所接受. 使用go语言开发的优秀的产品: Docker gocode lime ...