Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C#中,为什么字符串是一种行为类似于值类型的引用类型?_C#_String_Clr_Value Type_Reference Type - Fatal编程技术网

在C#中,为什么字符串是一种行为类似于值类型的引用类型?

在C#中,为什么字符串是一种行为类似于值类型的引用类型?,c#,string,clr,value-type,reference-type,C#,String,Clr,Value Type,Reference Type,字符串是引用类型,即使它具有值类型的大多数特征,例如不可变和重载==来比较文本,而不是确保它们引用相同的对象 为什么字符串不只是一种值类型呢?字符串不是值类型,因为它们可能很大,需要存储在堆中。值类型(到目前为止,在CLR的所有实现中)存储在堆栈上。堆栈分配字符串会破坏各种各样的东西:32位的堆栈只有1MB,64位的堆栈只有4MB,您必须对每个字符串进行装箱,这会导致复制惩罚,您无法对字符串进行实习,内存使用会膨胀,等等 (编辑:添加了关于值类型存储是一个实现细节的澄清,这导致了这种情况,即我们

字符串是引用类型,即使它具有值类型的大多数特征,例如不可变和重载==来比较文本,而不是确保它们引用相同的对象


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

字符串不是值类型,因为它们可能很大,需要存储在堆中。值类型(到目前为止,在CLR的所有实现中)存储在堆栈上。堆栈分配字符串会破坏各种各样的东西:32位的堆栈只有1MB,64位的堆栈只有4MB,您必须对每个字符串进行装箱,这会导致复制惩罚,您无法对字符串进行实习,内存使用会膨胀,等等


(编辑:添加了关于值类型存储是一个实现细节的澄清,这导致了这种情况,即我们有一个值语义不从System.ValueType继承的类型。谢谢Ben。)

它不是值类型,因为性能(空间和时间!)如果它是一个值类型,并且每次传递给方法或从方法返回时都必须复制它的值,那么这将是非常糟糕的

它具有保持世界正常的价值语义。你能想象如果

string s = "hello";
string t = "hello";
bool b = (s == t);

b
设置为
false
?想象一下,几乎任何应用程序的编码都是多么困难。

此外,字符串的实现方式(每个平台不同)以及何时开始将它们缝合在一起。就像使用
StringBuilder
。它为您分配了一个要复制的缓冲区,一旦您到达末尾,它将为您分配更多的内存,希望如果您执行大型串联,性能不会受到影响


也许Jon Skeet可以帮上忙?

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

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


至于“==”:正如您所说的“==”是一个运算符重载,实现它也是为了让框架在处理字符串时更有用。

这主要是一个性能问题

在编写代码时,让字符串的行为类似于值类型有助于提高性能,但让它成为值类型会对性能产生巨大影响


要深入了解,请看一看.net framework中的字符串。

如何判断
字符串是引用类型?我不确定如何实施它是否重要。C#中的字符串是不可变的,因此您不必担心这个问题。

不仅字符串是不可变的引用类型。 还有多播代理。 这就是为什么写作是安全的

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(字符串s)中。或者使用内存流


如果要创建一个库,希望在函数中传递大量字符串,请将参数定义为StringBuilder或流

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


这就是为什么字符串实际上是不可变的,因为当您更改它时,即使它的大小相同,编译器也不知道这一点,并且必须分配一个新数组并将字符分配给数组中的位置。如果您认为字符串是一种语言保护您不必动态分配内存的方式(阅读类似C的编程)

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

引用类型和值类型之间的区别基本上是语言设计中的性能权衡。引用类型在构造、销毁和垃圾收集方面有一些开销,因为它们是在堆上创建的。另一方面,值类型在赋值和方法调用上有开销(如果数据大小大于指针),因为整个对象复制到内存中,而不仅仅是指针。因为字符串可以(通常)比指针大很多,所以它们被设计为引用类型。此外,值类型的大小必须在编译时知道,这对于字符串来说并不总是如此

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

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

字符串文本(已知