为什么字符串是引用类型?

sel*_*raj 7 c# string reference-type primitive-types

为什么string是引用类型,即使它通常是原始数据类型,如int,float或double.

Eri*_*ert 18

除了Dan发布的原因:

根据定义,值类型是那些将值存储在自身中的类型,而不是在其他地方引用值.这就是为什么值类型被称为"值类型",而引用类型被称为"引用类型".所以你的问题实际上是"为什么字符串引用其内容而不是简单地包含其内容?"

这是因为值类型具有nice属性,即给定值类型的每个实例在内存中具有相同的大小.

所以呢?为什么这是一个不错的财产?好吧,假设字符串是可以是任何大小的值类型,请考虑以下内容:

string[] mystrings = new string[3];
Run Code Online (Sandbox Code Playgroud)

三个字符串数组的初始内容是什么?值类型没有"null",因此唯一明智的做法是创建一个包含三个空字符串的数组.怎么会在记忆中被列出来?想一想.你会怎么做?

现在假设你说

string[] mystrings = new string[3];
mystrings[1] = "hello";
Run Code Online (Sandbox Code Playgroud)

现在我们在数组中有"","hello"和"".内存在哪里"你好"去了吗? 分配给mystrings [1]的插槽有多大?数组及其元素的内存必须在某处.

这使CLR有以下选择:

  • 每次更改其中一个元素时都会调整数组大小,复制整个数据,大小可能是兆字节
  • 禁止创建未知大小的值类型数组
  • 禁止创建未知大小的值类型

CLR团队选择了后者.将字符串转换为引用类型意味着您可以有效地创建它们的数组.

  • 很遗憾我无法收藏答案。 (2认同)
  • @Ani:正确。*这就是引用类型*。唯一字段是引用的值类型和引用之间没有任何实际区别!显然它们具有完全相同的位,因为值类型的位只是其成员的位,并且如果它具有引用类型作为其成员,那么它只具有引用的位。如果位完全相同,那么为什么还要有这个结构呢?只要有参考并完成即可。 (2认同)

Dan*_*Tao 10

哎呀,这个答案得到了接受,然后我改变了.我应该在底部包括原始答案,因为这是OP所接受的.

新答案

更新:这就是事情.string 绝对需要表现得像一个引用类型.到目前为止,所有答案都触及了这个原因:string类型没有常量大小,将字符串的全部内容从一个方法复制到另一个方法是没有意义的,string[]否则数组必须调整主题大小 -仅举几个.

但是你仍然可以定义 stringstruct内部指向一个char[]数组甚至一个char*指针,并指出int它的长度,使它成为不可变的,瞧!,你有一个行为类似于引用类型但在技术上是值类型的类型.

老实说,这看起来很傻.正如Eric Lippert在其他答案的一些评论中指出的那样,定义这样的值类型与定义引用类型基本相同.几乎在所有意义上,它都与以相同方式定义的引用类型无法区分.

那么问题的答案"为什么是string参考类型?" 基本上是:"让它成为一种价值类型只会是愚蠢的." 但是,如果这是唯一的原因,那么,合乎逻辑的结论是,string实际上可以将其定义为struct如上所述,并且对于该选择没有特别好的论据.

然而,原因,它是更好地使string一个class比一个struct是比纯粹的智力了.这是我能想到的一对夫妇:

防止拳击

如果string是一个值类型,那么每当你将它传递给某个方法时,object它就必须装箱,这会产生一个新的object,这会使堆膨胀并导致无意义的GC压力.由于琴弦基本上无处不在,让它们一直引起装箱将是一个大问题.

用于直观的平等比较

是的,无论是引用类型还是值类型,string都可以覆盖Equals.但如果它是一个值类型,那么ReferenceEquals("a", "a")将返回false!这是因为两个参数都会被装箱,并且盒装参数永远不会有相同的引用(据我所知).

因此,即使你可以定义一个值类型,使其一个引用类型一样,它由一个引用类型字段组成,但它仍然不完全相同.所以我认为这是一个更完整的原因,为什么string是一个引用类型:你可以使它成为一个值类型,但这只会带来不必要的弱点.


原始答案

它是一个引用类型,因为只传递对它的引用.

如果它是值类型,则每次将字符串从一个方法传递到另一个方法时,整个字符串将被复制*.

因为它是一个引用类型,而不是像"Hello world!"这样的字符串值.传递 - "你好世界!" 顺便说一下,它是12个字符,这意味着它需要(至少)24个字节的存储空间 - 只传递对这些字符串的引用.传递引用比传递字符串中的每个字符要便宜得多.

而且,它实际上不是普通的原始数据类型.谁告诉你的?

*实际上,这并不严格.如果字符串内部拥有一个char[]数组,那么只要数组类型是引用类型,字符串的内容实际上就不会通过值传递 - 只有对数组的引用才是.不过,我仍然认为这基本上是正确的答案.

  • 实际上引用类型也是按值传递的,但它是引用本身而不是复制的对象. (2认同)