从如下几个方面总结一下C#的值类型与引用类型:编程
- 定义
- 值类型与引用类型的区别
- 值类型与引用类型的选择
- 拆装箱
- 如何避免拆装箱
.Net框架最主要的两个组成部分是CLR和框架类库(FCL),而CLR最主要的两个组成部分部分是CTS(公共类型系统)和CLS(公共语言规范)。简单来讲,CTS就是一种规范,它容许遵照此规范的编程语言能够存在什么类型,每种类型是否能够包含成员、以及能够包含哪些成员。官方给出的CTS做用以下:数组
- 创建用于跨语言执行的框架。
- 提供面向对象的模型,支持在 .NET 实现上实现各类语言。
- 定义处理类型时全部语言都必须遵照的一组规则。
- 提供包含应用程序开发中使用的基本基元数据类型(如 Boolean、Byte、Char 等)的库。
故,C#中的值类型与引用类型就遵循此规范。闭包
定义
- C# 中的数据类型能够简单的分为值类型(结构、枚举)和引用类型(类、接口、字符串、数组、委托、指针)。
- 值类型变量或常量的内容仅仅是一个值,例如整数int,小数float/double,布尔值等,换句话说就是,变量引用的位置就是值在内存中的位置。
- 引用类型比较复杂,它友两部分组成:对象和对象引用。而引用类型的变量中的内容存储的是对‘数据’存储位置的引用,不是直接存储‘数据’。
- 存储开销:
- 值类型所占内存大小就是存储字段所需内存。例如Book所需内存就是price、title、author内存的和。
- 引用类型要求为引用和对象单独分配存储空间。对象除占用了和字段同样的字节数以外,还须要额外的管理空间开销。
值类型实例的赋值老是会进行实例复制。 引用类型变量的赋值只会复制引用。 框架
查阅https://referencesource.microsoft.com,会发现 数值类型、布尔类型、字符类型 其实都属于Strust类型编程语言
值类型与引用类型的区别
- 全部值类型都隐式派生自System.ValueType,它是System.Object的子类,该类确保值类型全部的的成员所有分配在栈上。(如下三个除外)
- 结构体若是含有引用类型成员,该成员会牵扯到堆的分配
- 静态类型,若是一个变量时静态的,那么,不管她是什么类型,都会分配到加载堆上
- 局部变量被捕获升级为密封类(闭包中涉及到)
因此,“值类型都分配在栈上,引用类型都分配在堆上”是不许确的
- 引用类型初始值为null,值类型初始值为0.
- 值类型不能被继承,引用类型则能够
- 值类型的声明周期在其定义域内,离开定义域以后即被销毁,而引用类型没法肯定什么时候被销毁
装箱与拆箱
装箱与拆箱就是值类型与引用类型之间的转换性能
装箱过程
int i = 1;
object o = i;
复制代码
- 在堆中申请内存,内存大小为值类型大小,载加上额外的固定空间(类型对象指针和同步块索引)
- 将值类型的字段值拷贝到新申请的内存中
- 返回新引用对象的内存地址
装箱须要比原数据更多的空间, 由于它须要两个引用类型的标准配置:类型对象指针和同步块索引spa
拆箱过程
int b = (int) o;
复制代码
- 检查引用类型是否为null,不然抛出NullReferenceException异常。检查对象实例,确保它是给定值类型的一个装箱值。不然抛出InvaildCastException异常。
- 将该值的实例复制到值类型变量中。
与拆箱比较,装箱的性能消耗更大,由于引用对象的分配更复杂,成本也就更高,值类型分配在堆栈上,分配和释放的效率都很高。指针