CLR via C#(02)-基元类型、引用类型、值类型
http://www.cnblogs.com/qq0827/p/3281150.html
一、 基元类型
编译器能够直接支持的数据类型叫做基元类型。例如int, string等。基元类型和.NET框架类库FCL存在着直接的映射关系。
string和String?
面试的时候曾经被问到过这个问题,C#中的基元类型string实际上对应了System.String(FCL)类型,所以两者使用的时候没有什么不同。
类型转换
编译器能够在基元类型之间进行显式或隐式转换。如果转换是安全的,也就是转换过程不会造成数据丢失,则可以直接采用隐式转换。如果是不安全的,则必须采用显式转换。
Int32 a=5;
Int64 b=a;
Int32 c=(Int32)b;
二、 引用类型和值类型
引用类型和值类型的区别:
|
引用类型 |
值类型 |
|
从托管堆中分配 |
从线程的堆栈中分配 |
|
对象考虑垃圾回收机制 |
不考虑垃圾回收机制 |
|
所有类都是引用 |
结构或枚举都是值类型 |
|
继承自System.ValueType |
|
|
只有装箱形式 |
有两种形式:装箱和未装箱 |
|
可以继承和派生 |
不能作为基类,不能有虚方法 |
|
引用类型变量初始化时默认为null |
初始化时默认为0值 |
|
复制时只拷贝内存地址 |
复制时“字段对字段”的拷贝 |
结构体直接继承自System.ValueType;而枚举直接继承自System.Enum, Enum类又直接继承自System.ValueType。
下面通过例子看一下他们的区别:
首先定义类和结构体:
class SomeRef { public Int32 x; }
struct SomeVal { public Int32 x; }
SomeRef r1 = new SomeRef(); // 分配到堆
SomeVal v1 = new SomeVal(); // 分配到栈
r1.x =5; // 所引用的堆空间内数据修改
v1.x =5; // 直接在栈上复赋值
Console.WriteLine(r1.x); // "5"
Console.WriteLine(v1.x); // "5"
SomeRef r2 = r1; //只把指针复制给了r2
SomeVal v2 = v1; // 在栈上分配空间,并且将变量内容进行复制
r1.x = 8; // r1指向(也是r2指向)的内容修改
v1.x = 9; // 只修改v1内容,v2内容不会受影响
Console.WriteLine(r1.x); // "8"
Console.WriteLine(r2.x); // "8"
Console.WriteLine(v1.x); // "9"
Console.WriteLine(v2.x); // "5"
看看下图的内存分配情况,就一目了然了。

三、 值类型的装箱与拆箱
1. 装箱过程?
装箱:将值类型转换为引用类型。当我们把值类型参数传递给需要引用类型参数的方法时,会自动进行装箱操作。过程如下:
- 从托管堆为要生成的引用类型分配大小。大小为:值类型实例本身的大小+额外空间(方法表指针和SyncBlockIndex)。
- 将值类型字段拷贝到刚刚分配的内存中。
- 返回托管堆中新分配内存的地址。也就是指向对象的引用。
2. 拆箱过程?
拆箱:获取指向对象中包含的值类型部分的指针。一般拆箱之后会进行字段拷贝操作,两个操作加起来才是真正与装箱互反的操作。过程如下:
- 如果引用为Null,则抛出NullReferenceException异常。
- 如果引用对象不是一个期望值类型的已装箱对象,会抛出InvalidCastException异常。
- 返回一个指向包含在已装箱对象中值类型部分的指针。
3. 实例
- 拆箱的转型结果必须是它原来未装箱时的类型。
public static void Main() {
Int32 x = 5;
Object o = x; // 装箱
Int16 y = (Int16) o; // 拆箱,抛出InvalidCastException异常
}
修正:Int16 z=(Int16)(Int32)o;//拆箱成功
- 这段代码进行了几次装箱?
public static void Main() {
Int32 v = 5; // 创建值变量
Object o = v; // 装箱
v = 123; // Changes the unboxed value to 123
Console.WriteLine(v + ", " + (Int32) o); // Displays "123, 5" ,装箱两次
}
上面的代码进行了3次装箱,最后一行中v被装箱为引用类型,o首先被拆箱然后再装箱为引用类型。
我们看一下它的IL代码:

字符串连接实际上调用的是Concat方法,该方法的参数要求是object,因此各参数都要转换成object类型。
优化:
Console.WriteLine(v.ToString()+”,”+o);//装箱0次
我们要尽量少的进行值类型的装箱拆箱操作,以提高程序性能。
作者:丫头小静(Cathy)
出处:http://www.cnblogs.com/janes/
博客文章仅供交流学习,请勿用于商业用途。如需转载,请务必注明出处。
CLR via C#(02)-基元类型、引用类型、值类型的更多相关文章
- [Clr via C#读书笔记]Cp5基元类型引用类型值类型
Cp5基元类型引用类型值类型 基元类型 编译器直接支持的类型,基元类型直接映射到FCL中存在的类型. 作者希望使用FCL类型名称而避免使用关键字.他的理由是为了更加的清晰的知道自己写的类型是哪种.但是 ...
- 重温CLR(四)基元类型、引用类型、值类型
编程语言的基元类型 编译器直接支持的数据类型称为基元类型(primitive type).基元类型直接映射到framework类型(fcl)中存在的类型. 下表列出fcl类型 从另一个角度,可以认为C ...
- C#中的基元类型、值类型和引用类型
C# 中的基元类型.值类型和引用类型 1. 基元类型(Primitive Type) 编译器直接支持的类型称为基元类型.基元类型可以直接映射到 FCL 中存在的类型.例如,int a = 10 中的 ...
- [No0000B5]C# 类型基础 值类型和引用类型 及其 对象判等 深入研究1
引言 本文之初的目的是讲述设计模式中的 Prototype(原型)模式,但是如果想较清楚地弄明白这个模式,需要了解对象克隆(Object Clone),Clone其实也就是对象复制.复制又分为了浅度复 ...
- [No0000B9]C# 类型基础 值类型和引用类型 及其 对象复制 浅度复制vs深度复制 深入研究2
接上[No0000B5]C# 类型基础 值类型和引用类型 及其 对象判等 深入研究1 对象复制 有的时候,创建一个对象可能会非常耗时,比如对象需要从远程数据库中获取数据来填充,又或者创建对象需要读取硬 ...
- C#的两种类据类型:值类型和引用类型
注:引用类型相等赋值是地址赋值,不是值赋值. 什么是值类型,什么是引用类型 概念:值类型直接存储其值,而引用类型存储对其值的引用.部署:托管堆上部署了所有引用类型. 引用类型:基类为Objcet 值类 ...
- CLR-2-2-引用类型和值类型
引用类型和值类型,是一个老生常谈的问题了.装箱拆箱相信也是猿猿都知,但是还是跟着CLR via C#加深下印象,看有没有什么更加根本和以前被忽略的知识点. 引用类型: 引用类型有哪些这里不过多赘述,来 ...
- EXISTS 执行顺序 CLR-2-2-引用类型和值类型
EXISTS 执行顺序 select * from a where a.s_status=1 and exists (select orderid from b on a.orderid=b.or ...
- 脚踏实地学C#2-引用类型和值类型
引用类型和值类型介绍 CLR支持两种类型,引用类型和值类型两种基本的类型: 值类型下有int.double.枚举等类型同时也可以称为结构,如int结构类型.double结构类型,所有的值类型都是隐式密 ...
- Docs-.NET-C#-指南-语言参考-关键字-内置类型-值类型:值类型的功能
ylbtech-Docs-.NET-C#-指南-语言参考-关键字-内置类型-值类型:值类型的功能 1.返回顶部 1. 值类型(C# 参考) 2018/11/26 有两种值类型: 结构 枚举 值类型的主 ...
随机推荐
- UIMenuController使用
- (void)bubbleDidLongPress:(UILongPressGestureRecognizer *)gestureRecognizer { if(gestureRecognizer. ...
- ios7 ios8导航栏透明
自动调整scrollview的insets为0, 然后scrollview就不会向下偏移64px self.automaticallyAdjustsScrollViewInsets = NO; 导航栏 ...
- 交叉编译inetutils并配置telnet服务
inetutils集成了许多网络客户和服务程序,主要有,finger, ftp, ftpd, rcp, rexec, rlogin, rlogind, rsh, rshd, syslog,syslog ...
- 线程池大小 & cpu core
http://stackoverflow.com/questions/14556037/number-of-processor-core-vs-the-size-of-a-thread-pool ht ...
- Oracle占用8080端口问题的解决
可能在本地同时安装过Tomcat和Oracle的人都会知道,安装完Oracle后,会发现Tomcat的8080端口已经被Oracle占用了. 完全安装Oracle数据库后,当我们访问8080端口时,会 ...
- Delete a node from BST
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Retur ...
- mysql中表名是order的CRUD的错误
org.springframework.jdbc.BadSqlGrammarException: ### Error querying database. Cause: com.mysql.jdbc. ...
- zju3545
AC自动机+状态压缩DP 注意:相同的串可能出现多次,如果匹配成功则将各次权值加和. #include <cstdio> #include <queue> #include & ...
- Java RuntimeException异常处理汇总
Java中所有异常的父类是Throwable类,在Throwable类下有两大子类: 一个是Error类,指系统错误异常,例如:VirtualMachineError 虚拟机错误,ThreadDeat ...
- Innodb锁机制:Next-Key Lock 浅谈
数据库使用锁是为了支持更好的并发,提供数据的完整性和一致性.InnoDB是一个支持行锁的存储引擎,锁的类型有:共享锁(S).排他锁(X).意向共享(IS).意向排他(IX).为了提供更好的并发,Inn ...