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

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


当前回答

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

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.

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

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

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

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

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

其他回答

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

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。

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

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

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.

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

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

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

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

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

这主要是性能问题。

在编写代码时,让字符串的行为像值类型一样有帮助,但如果它是值类型,则会对性能造成巨大影响。

要深入了解,请参阅一篇关于.net框架中字符串的好文章。

并不像字符串由字符数组组成那么简单。我把字符串看作字符数组[]。因此,它们位于堆上,因为引用内存位置存储在堆栈上,并且指向数组在堆上内存位置的开始。字符串大小在分配之前是不知道的…非常适合堆。

这就是为什么字符串是不可变的,因为当你改变它时,即使它的大小相同,编译器也不知道,它必须分配一个新的数组,并将字符分配到数组中的位置。如果你认为字符串是语言保护你不需要动态分配内存的一种方式,这是有道理的(像编程一样阅读C语言)