为什么string是引用类型,即使它通常是原始数据类型,如int,float或double。
答案 0 :(得分:18)
除了Dan发布的原因外:
值类型是按照定义那些将值存储在自身中的类型,而不是将引用到其他地方的值。这就是为什么值类型被称为“值类型”,而引用类型被称为“引用类型”。所以你的问题实际上是“为什么字符串引用其内容而不是简单地包含其内容?”
这是因为值类型具有nice属性,给定值类型的每个实例在内存中具有相同的大小。
那又怎样?为什么这是一个不错的财产?好吧,假设字符串是可以是任何大小的值类型,请考虑以下内容:
string[] mystrings = new string[3];
三个字符串数组的初始内容是什么?值类型没有“null”,因此唯一明智的做法是创建一个包含三个空字符串的数组。怎么会在记忆中被列出来?想一想。你会怎么做?
现在假设你说
string[] mystrings = new string[3];
mystrings[1] = "hello";
现在我们在数组中有“”,“hello”和“”。 在内存中“hello”的位置是什么?无论如何,为mystrings [1]分配的插槽有多大?数组及其元素的内存必须某处。
这使CLR有以下选择:
CLR团队选择了后者。 将字符串设置为引用类型意味着您可以有效地创建它们的数组。
答案 1 :(得分:10)
Yikes,这个答案被接受,然后我改变了它。我应该在底部包含原始答案,因为那是OP所接受的。
更新:这就是问题所在。 string
绝对需要表现为引用类型。到目前为止,所有答案都触及了这个原因:string
类型没有常量大小,将字符串的全部内容从一个方法复制到另一个方法是没有意义的,{{1}否则,数组必须调整主题大小 - 仅举几例。
但您仍然可以定义 string[]
作为string
,内部指向struct
数组甚至是char[]
指针和{ {1}}为了它的长度,让它变成不可变的,并且瞧!,你有一个类型,的行为类似于一个引用类型,但技术上 em>值类型。
老实说,这看起来很傻。正如Eric Lippert在其他答案的一些评论中指出的那样,定义这样的值类型与定义引用类型基本相同。几乎在所有意义上,它都与以相同方式定义的引用类型无法区分。
所以问题的回答“为什么char*
是引用类型?”基本上是:“让它成为一种价值类型只会是愚蠢的。”但如果那只是唯一的原因,那么真正的逻辑结论是int
实际上可以被定义为如上所述的string
并且没有特别好的论据反对那种选择。
然而,是的原因,最好让string
成为struct
,而不是string
,而不仅仅是纯粹的知识分子。这是我能想到的一对夫妇:
如果class
是一个值类型,那么每次将它传递给期望struct
的某个方法时,都必须装箱,这会创建一个新的string
,膨胀堆并导致无意义的GC压力。由于字符串基本上无处不在,因此让它们一直引起装箱将是一个大问题。
是的,object
可以覆盖object
,无论它是引用类型还是值类型。但是如果是值类型,那么string
将返回 false !这是因为两个参数都会被装箱,并且盒装参数永远不会有相同的参考(据我所知)。
所以,即使你可以定义一个值类型来执行就像引用类型一样,它由一个引用类型字段组成,但它仍然不是 一样。所以我认为这是Equals
作为引用类型的更完整的原因:你可以使它成为一个值类型,但这只会给它带来不必要的弱点。
它是一种引用类型,因为只传递引用。
如果是值类型,则每次将字符串从一个方法传递到另一个方法时,整个字符串都将被复制*。
因为它是一个引用类型,而不是像“Hello world!”这样的字符串值。传递 - “你好世界!”顺便说一下,它是12个字符,这意味着它需要(至少)24个字节的存储空间 - 只传递引用来传递这些字符串。传递引用比传递字符串中的每个字符要便宜得多。
此外,它实际上不是正常的原始数据类型。是谁告诉你的?
*实际上,这并不严格。如果字符串内部持有ReferenceEquals("a", "a")
数组,那么只要数组类型是引用类型,字符串的内容实际上不将按值传递 - 仅引用数组将是。不过,我仍然认为这基本上是正确答案。
答案 2 :(得分:1)
String是引用类型,而不是值类型。在许多情况下,您知道字符串的长度和字符串的内容,在这种情况下,很容易为字符串分配内存。但请考虑这样的事情。
string s = Console.ReadLine();
是否无法在编译时知道“s”的分配细节。用户输入值,所有输入的字符串/行都存储在s中。因此,字符串存储在堆上,以便重新分配内存以适合字符串s的内容。并且对此字符串的引用存储在堆栈中。
要了解更多信息,请阅读:petzold的.net零
读取:从CLR通过C#收集垃圾以获取堆栈上的分配详细信息。
编辑:Console.WriteLine();到Console.ReadLine();