String是一种引用类型,尽管它具有值类型的大多数特征,例如不可变和重载==以比较文本,而不是确保它们引用同一个对象。

为什么字符串不只是一个值类型呢?


当前回答

实际上,字符串与值类型几乎没有相似之处。对于初学者来说,并不是所有的值类型都是不可变的,你可以随心所欲地改变Int32的值,而它在堆栈上的地址仍然是相同的。

字符串是不可变的有一个很好的理由,这与它是引用类型无关,但与内存管理有很大关系。当字符串大小发生变化时,创建一个新对象比在托管堆上移动对象更有效。我认为你把值/引用类型和不可变对象的概念混在一起了。

至于“==”:就像你说的,“==”是一个操作符重载,它的实现有一个很好的理由,使框架在处理字符串时更有用。

其他回答

如何知道字符串是引用类型?我不确定它是如何实施的。c#中的字符串是不可变的,所以你不必担心这个问题。

这是对一个老问题的迟来的回答,但所有其他的回答都忽略了一点,那就是。net直到2005年的。net 2.0才有泛型。

String是一种引用类型,而不是值类型,因为对于Microsoft来说,确保字符串能够以最有效的方式存储在非泛型集合(如System.Collections.ArrayList)中至关重要。

在非泛型集合中存储值类型需要对类型对象进行特殊的转换,这种转换称为装箱。当CLR装箱一个值类型时,它将该值包装在系统中。对象,并将其存储在托管堆上。

从集合中读取值需要反向操作,称为开箱操作。

装箱和拆箱都有不可忽略的成本:装箱需要额外的分配,拆箱需要类型检查。

一些答案错误地声称字符串永远不可能被实现为值类型,因为它的大小是可变的。实际上,将字符串实现为包含两个字段的固定长度数据结构是很容易的:字符串长度的整数和指向char数组的指针。你也可以在此基础上使用小字符串优化策略。

如果泛型从第一天就存在,我想将字符串作为值类型可能是一个更好的解决方案,具有更简单的语义,更好的内存使用和更好的缓存位置。只包含小字符串的List<string>可能是单个连续的内存块。

不仅字符串是不可变的引用类型。 还有多类型转换委托。 这就是为什么写信是安全的

protected void OnMyEventHandler()
{
     delegate handler = this.MyEventHandler;
     if (null != handler)
     {
        handler(this, new EventArgs());
     }
}

我认为字符串是不可变的,因为这是使用它们和分配内存的最安全的方法。 为什么它们不是值类型?以前的作者对堆栈大小等的看法是正确的。我还会添加,使字符串引用类型允许在程序中使用相同的常量字符串时节省程序集大小。如果你定义

string s1 = "my string";
//some code here
string s2 = "my string";

“my string”常量的两个实例很可能只在程序集中分配一次。

如果你想像一般引用类型一样管理字符串,把字符串放在一个新的StringBuilder(string s)中。或者使用MemoryStreams。

如果您要创建一个库,并希望在函数中传递一个巨大的字符串,则可以将参数定义为StringBuilder或Stream。

字符串是具有值语义的引用类型。这种设计是一种折衷,允许某些性能优化。

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.

但是字符串有值语义,这意味着它们是不可变的,并通过值(即字符串的字符逐个字符)进行比较,而不是通过比较引用。这允许某些优化:

实习意味着如果已知多个字符串相等,编译器可以只使用一个字符串,从而节省内存。这种优化只在字符串不可变的情况下有效,否则更改一个字符串将对其他字符串产生不可预测的结果。

字符串字面值(在编译时已知)可以被编译器存储在内存的一个特殊静态区域中。这节省了运行时的时间,因为它们不需要分配和垃圾收集。

不可变字符串确实会增加某些操作的成本。例如,您不能就地替换单个字符,必须为任何更改分配一个新字符串。但与优化的好处相比,这是一个很小的成本。

值语义有效地为用户隐藏了引用类型和值类型之间的区别。如果一个类型具有值语义,那么该类型是值类型还是引用类型对用户来说并不重要——它可以被视为一个实现细节。

此外,字符串的实现方式(每个平台都不同)以及何时开始将它们拼接在一起。就像使用StringBuilder一样。它为你分配了一个缓冲区供你复制,一旦你到达终点,它会为你分配更多的内存,希望如果你做一个大的连接性能不会受到阻碍。

也许乔恩·斯基特可以过来帮忙?