String是一种引用类型,尽管它具有值类型的大多数特征,例如不可变和重载==以比较文本,而不是确保它们引用同一个对象。
为什么字符串不只是一个值类型呢?
String是一种引用类型,尽管它具有值类型的大多数特征,例如不可变和重载==以比较文本,而不是确保它们引用同一个对象。
为什么字符串不只是一个值类型呢?
当前回答
字符串不是值类型,因为它们可能很大,需要存储在堆上。值类型(在CLR的所有实现中)存储在堆栈上。堆栈分配字符串会破坏各种各样的事情:32位的堆栈只有1MB, 64位的堆栈只有4MB,你必须装箱每个字符串,导致复制惩罚,你不能实习字符串,内存使用会膨胀,等等……
(编辑:增加了关于值类型存储是实现细节的说明,这导致了这种情况,即我们有一个具有值语义的类型没有从System.ValueType继承。由于本。)
其他回答
它不是一个值类型,因为如果它是一个值类型,并且它的值每次传递给方法或从方法返回时都必须复制,那么性能(空间和时间!)会很糟糕。
它有价值语义来保持世界的理智。你能想象编码有多困难吗
string s = "hello";
string t = "hello";
bool b = (s == t);
设b为假?想象一下编写任何应用程序是多么困难。
字符串是具有值语义的引用类型。这种设计是一种折衷,允许某些性能优化。
The distinction between reference types and value types are basically a performance tradeoff in the design of the language. Reference types have some overhead on construction and destruction and garbage collection, because they are created on the heap. Value types on the other hand have overhead on assignments and method calls (if the data size is larger than a pointer), because the whole object is copied in memory rather than just a pointer. Because strings can be (and typically are) much larger than the size of a pointer, they are designed as reference types. Furthermore the size of a value type must be known at compile time, which is not always the case for strings.
但是字符串有值语义,这意味着它们是不可变的,并通过值(即字符串的字符逐个字符)进行比较,而不是通过比较引用。这允许某些优化:
实习意味着如果已知多个字符串相等,编译器可以只使用一个字符串,从而节省内存。这种优化只在字符串不可变的情况下有效,否则更改一个字符串将对其他字符串产生不可预测的结果。
字符串字面值(在编译时已知)可以被编译器存储在内存的一个特殊静态区域中。这节省了运行时的时间,因为它们不需要分配和垃圾收集。
不可变字符串确实会增加某些操作的成本。例如,您不能就地替换单个字符,必须为任何更改分配一个新字符串。但与优化的好处相比,这是一个很小的成本。
值语义有效地为用户隐藏了引用类型和值类型之间的区别。如果一个类型具有值语义,那么该类型是值类型还是引用类型对用户来说并不重要——它可以被视为一个实现细节。
事实上,许多人提到的堆栈和内存是关于值类型和基本类型的,因为它们必须适合微处理器中的寄存器。如果它占用的比特数超过了一个寄存器....的比特数,那么您就不能向堆栈中插入或从堆栈中取出某个东西例如,这些指令是“pop eax”——因为eax在32位系统上是32位宽的。
浮点基元类型由80位宽的FPU处理。
这早在OOP语言混淆原始类型定义之前就已经确定了,我认为值类型是专门为OOP语言创建的术语。
简单地说,任何具有一定大小的值都可以被视为值类型。
这是对一个老问题的迟来的回答,但所有其他的回答都忽略了一点,那就是。net直到2005年的。net 2.0才有泛型。
String是一种引用类型,而不是值类型,因为对于Microsoft来说,确保字符串能够以最有效的方式存储在非泛型集合(如System.Collections.ArrayList)中至关重要。
在非泛型集合中存储值类型需要对类型对象进行特殊的转换,这种转换称为装箱。当CLR装箱一个值类型时,它将该值包装在系统中。对象,并将其存储在托管堆上。
从集合中读取值需要反向操作,称为开箱操作。
装箱和拆箱都有不可忽略的成本:装箱需要额外的分配,拆箱需要类型检查。
一些答案错误地声称字符串永远不可能被实现为值类型,因为它的大小是可变的。实际上,将字符串实现为包含两个字段的固定长度数据结构是很容易的:字符串长度的整数和指向char数组的指针。你也可以在此基础上使用小字符串优化策略。
如果泛型从第一天就存在,我想将字符串作为值类型可能是一个更好的解决方案,具有更简单的语义,更好的内存使用和更好的缓存位置。只包含小字符串的List<string>可能是单个连续的内存块。