c# 值类型和引用类型

2021-02-17  本文已影响0人  wwmin_

一、值类型和引用类型的基础知识

值类型和引用类型的区别在于变量的值在它声明时的存储位置。局部变量的值总是存储在栈(stack)中,实例变量的值总是存储在实例本身存储的地方。引用类型实例(对象)总是存储在堆(heap)中,静态变量也是在堆中。
两种类型的另一个差异在于,值类型不可以派生出其他类型。这将导致的一个结果就是,值不需要额外的信息来描述值实际是什么类型。把它同引用类型比较,对于引用类型来说,每个对象的开头都包含一个数据块,它标识了对象的实际数据,同时还提供了其他一些信息。
引用本身并不知道对象的类型-所以同一个引用“值”可用于(引用)不同类型的多个变量。如下:

Stream stream = new MemoryStream();
MemoryStream memoryStream = (MemoryStream) stream;

第1行创建的一个新的MemoryStream对象,将stream变量的值设为对那个新对象的引用。
第2行检查stream的值引用的是不是一个MemoryStream(或派生类型)对象,并将MemoryStream的值设为相同的值。

二、值类型和引用类型的误区

误区1. “结构是轻量级的类”

有人认为值类型不能或不应有方法或其他有意义的行为 - 他们应作为简单的数据转移类型来使用,只应该有public字段或简单的属性。
对于这个说法,一个非常典型的反例就是DateTime类型:它作为值类型来提供是很有道理的,因为它非常适合作为和数字或字符相似的一个基本单位来使用。另外,它也理应被赋予对它的值执行计算的能力。

误区2. “引用类型保存在堆上,值类型保存在栈上”

第一部分是正确的--引用类型的实例总是在堆上创建的。但第二部分就有问题了。变量的值是在它声明的位置存储的。所以,假定一个类中有一个int类型的实例变量,那么在这个类的任何对象中,该变量的值总是和对象中的其他数据在一起,也就是在堆上。只有局部变量(方法内部声明的变量)和方法参数在栈上。对于c#2及以上版本,很多局部变量并不完全存放在栈上。

误区3. “对象在C#中默认是通过引用传递的”

无论是引用传递还是值传递,永远不会传递对象本身。涉及一个引用类型时,要么以“引用传递”的方式传递变量,要么以“传值”的方式传递参数值(引用)。

三、装箱和拆箱

int i = 5;
object 0 = i;
int j = (int) o;

i是值类型变量,0是引用类型变量。o的值是一个引用,而i不是引用,它是一个整数值。实际发生的事情就是装箱:运行时将在堆上创建一个包含值(5)的对象(它是一个普通对象)。o的值是对该对象的一个引用。该对象的值是原始值的一个副本,改变i的值不会改变箱内的值。同样拆箱也会复制箱内的值,在赋值之后,j和对象之间不再有任何关系。
之所以要留意装箱和拆箱,是由于他们可能会降低性能。多次装箱拆箱会创建众多对象,而这些对象会加重垃圾回收期的负担。

摘选自《深入理解C# (第3版)》第2章

本文作者:wwmin
微信公众号: DotNet技术说
本文链接:https://www.jianshu.com/p/c20686834877
关于博主:评论和私信会在第一时间回复。或者[直接私信]我。
版权声明:转载请注明出处!
声援博主:如果您觉得文章对您有帮助,关注点赞, 您的鼓励是博主的最大动力!

上一篇 下一篇

猜你喜欢

热点阅读