哎呀,这个答案被接受了,然后我改变了它。我可能应该在底部包含原始答案,因为这是 OP 所接受的。
新答案
更新:事情是这样的。 string 绝对需要表现得像引用类型。到目前为止,所有答案都提到了造成这种情况的原因:string 类型没有固定大小,将字符串的全部内容从一种方法复制到另一种方法是没有意义的,string[] 数组否则会必须调整主题的大小——仅举几例。
但您仍然可以定义 string 为 struct 内部指向 char[] 数组甚至是 char* 指针和 int 的长度,让它不可变,并且瞧!,您将拥有一个行为类似于引用类型但技术上是值类型的类型。
老实说,这看起来很愚蠢。正如 Eric Lippert 在其他答案的一些 cmets 中指出的那样,定义这样的值类型与定义引用类型基本相同。在几乎所有意义上,它都与以相同方式定义的引用类型没有区别。
所以“为什么string 是引用类型?”这个问题的答案是什么?基本上是:“让它成为一个值类型只是愚蠢的。”但如果这是唯一的原因,那么实际上,合乎逻辑的结论是string 实际上可以被定义为如上所述的struct,并且没有特别好的论据反对这种选择。
但是,有 个原因表明,将 string 制作成 class 比制作 struct 更好,这不仅仅是纯粹的智力。以下是我能想到的几个:
为了防止拳击
如果string 是一个值类型,那么每次你将它传递给某个期望object 的方法时,它都必须被装箱,这将创建一个新的object,这会使堆膨胀并导致毫无意义气相色谱压力。由于字符串基本上无处不在,让它们一直导致装箱将是一个大问题。
用于直观的相等比较
是的,string 可以覆盖 Equals,无论它是引用类型还是值类型。但是如果它是一个值类型,那么ReferenceEquals("a", "a") 会返回false!这是因为两个参数都会被装箱,而装箱的参数从不有相同的引用(据我所知)。
因此,即使您确实可以定义一个值类型,使其就像一个引用类型,通过让它包含一个引用类型字段,但它仍然不是完全 一样。因此,我认为这是 string 是引用类型的更完整原因:您可以将其设为值类型,但这只会给它带来不必要的弱点。
原答案
这是一个引用类型,因为只有对它的引用会被传递。
如果它是一个值类型,那么每次你将一个字符串从一个方法传递到另一个方法时,整个字符串都会被复制*。
因为它是一个引用类型,而不是像“Hello world!”这样的字符串值被传递——“世界你好!”顺便说一下,它是 12 个字符,这意味着它需要(至少)24 个字节的存储空间——只有对这些字符串的 references 被传递。传递引用比传递字符串中的每个字符要便宜得多。
而且,它真的不是一个普通的原始数据类型。谁告诉你的?
*实际上,这并不完全正确。如果字符串内部包含一个char[] 数组,那么只要数组类型是引用类型,字符串的内容实际上不会按值传递——只有对数组的引用将会。不过,我仍然认为这基本上是正确的答案。