C#中值类型和引用类型有什么区别?

10

我知道几个区别:

  1. 值类型存储在栈上,而引用类型存储在托管堆上。
  2. 值类型变量直接包含它们的值,而引用变量只包含指向托管堆上创建的对象位置的引用。

还有其他我漏掉的差异吗?如果有,是什么?


8
已经在SO上问了很多次了... - Mitch Wheat
@Wheat,快速搜索后发现,这个问题并没有直接被询问或回答。 - strager
3
目前我没有足够的时间对此进行全面回答,但我想指出“值类型存储在堆栈上”这种说法有些夸张。请参阅http://pobox.com/~skeet/csharp/memory.html了解更多关于引用类型和值类型的信息。如需了解更多关于引用类型与值类型之间的差异,请查看http://pobox.com/~skeet/csharp/references.html。 - Jon Skeet
@strager - 措辞略有不同,但这个主题在很多地方都有涉及。例如:https://dev59.com/g0jSa4cB1Zd3GeqPFW8_ - Mike Two
值类型在装箱时可以存储在堆上。http://msdn.microsoft.com/zh-cn/library/yz2be5wk.aspx - Zaid Masud
4个回答

22
请阅读:堆栈是一个实现细节,并且不要再重复错误认为在.NET中,值类型与引用类型的区别在于堆栈分配。CLR可以选择在任何地方分配变量。
最重要的区别在于赋值语义。当您将值类型赋给一个变量(或将它作为参数传递给方法时),所有数据都将被复制。当您将引用类型赋值时,只会复制一个引用-两个引用指向内存中的同一对象实例。

有点严厉,但这是我学习的最好方法,就像如果你惹恼了甘道夫并等着他用恼怒的声音向你解释一样,它往往会牢记在心中 =D - Paul C

15

以下是一些额外的区别:

  1. 值类型无法被继承,而引用类型可以。
  2. 值类型实现为结构体,引用类型实现为类。
  3. 值类型默认情况下不能分配真正的 null 值(? 语法是一种解决方法,但仍未得到真正的 null 值)。
  4. 将值类型赋值给另一个变量或将其作为参数传递给方法时,会复制一份副本,而对于引用类型,变量表示对象的内存位置。
  5. 在结构体中声明显式无参构造函数是编译时错误,但对于类则不适用。
  6. 在结构体中使用 "this" 对象之前未分配所有字段是编译时错误,但对于类则不适用。
  7. 在结构体中未完全分配所有属性的构造函数是编译时错误,但对于类则不适用。

2
如Aaronaught和Eric的博客文章所提到的:
记住这个规则,引用类型总是放在堆上,而值类型总是放在它们被声明的地方?如果一个值类型在方法外部被声明,但在引用类型内部,则会被放置在堆上的引用类型中。

0

我认为值类型会隐式地分配内存,但是引用类型必须显式地分配内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接