随笔 - 272  文章 - 7  评论 - 27  阅读 - 83万

c#数据类型之值类型和引用类型

    C#数据类型分隔为值类型和引用类型。而所用数据类型都继承自Object

1. 值类型继承自System.ValueType,引用类型继承自System.Object。ValueType也直接继承自Object。如图:

   每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值,注意所有的值类型都是密封(sealed)的,所以无法派生出新的值类型。而且System.ValueType 本身是一个类类型,而不是值类型,因为它重写了 Object.Equals(Object),所以对值类型将按照实例的值来比较,而不是 比较引用地址。 
   值类型直接存储其值,变量本身就包含了其实例数据,而引用类型保存的只是实例数据的内存引用。 因此,一个值类型变量就永远不会影响到其他的值类型变量,而两个引用类型变量则很有可能指向同一地址,从而发生相互影响。

2. 从内存分配上来看,值类型通常分配在线程的堆栈上,作用域结束时,所占空间自行释放,效率高,无需进行地址转换,而引用类型通常分配在托管堆上,由 GC 来控制其回收,需要进行地址转换,效率降低,这也正是c#需要定义两种数据类型的原因之一。c#中值类型变量直接把变量的值保存在堆栈中,引用类型的变量把实际数据的地址保存在堆栈中,而实际数据则保存在堆中。

    注:栈是操作系统分配的一个连续的内存区域,用于快速访问数据。因为值类型的容量是已知的,因此它 可存储在栈上。而托管堆是 CLR 在应用程序启动时为应用程序预留的一块连续内存区,是用于动态内存分 配的内存区,引用类型的容量只有到运行时才能确定,所以用堆来存储引用类型。 栈的内存分配是自动释放;而堆在.NET中会有GC来释放 。

3.相互转换(装箱/拆箱).

   C# 的通用类型系统(Common Type System),使得值类型可以转化为对象来处理,这就是常说的装箱和拆箱。由于装拆箱需要装建全新对象或做强制类型转换,这些操作所需时间和运算要远远大于赋值操作,因此不提倡 使用它,同时也要尽量避免隐式装拆箱的发生。如前面所述,值类型要么是堆栈分配的,要么是在结构中以内联方式分配的。引用类型是堆分配的。当值类型需要充当对象时,CTS就在堆上分配一个包装(该包装能使值类型看上去像引用对象一样)并且将该值类型的值复制给它。该包装被加上标记,以便系统知道它包含一个值类型。这个进程称为装箱,其反向进程称为取消装箱。装箱和取消装箱能够使任何类型像对象一样进行处理。

 

posted on   NLazyo  阅读(358)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示