C#中的字符串赋值

几周前,我发现C#中的字符串被定义为引用类型而不是值类型。 最初我对此感到困惑,但经过一些阅读后,我突然明白为什么将字符串存储在堆而不是堆栈上是很重要的 – 因为将非常大的字符串复制到不可预测的数字上会非常低效堆栈帧。 我完全接受了。

我觉得我的理解几乎已经完成了,但是我缺少一个元素 – 字符串用什么语言来保持它们不变? 用代码示例来说明:

string valueA = "FirstValue"; string valueB = valueA; valueA = "AnotherValue"; Assert.AreEqual("FirstValue", valueB); // Passes 

当我将valueA分配给valueB时,我不明白哪个语言function会复制valueA。 或者,当我将valueA赋值给valueB时,对valueA的引用不会改变,只有valueA在我设置字符串时获得对它自身的新引用。 由于这是一个实例类型,我不明白为什么这样做。

我知道你可以重载,例如,==和!=运算符,但我似乎找不到有关重载=运算符的任何文档。 解释是什么?

字符串使用什么语言function来保持它们不可变?

它不是语言function。 这是课程的定义方式。

例如,

 class Integer { private readonly int value; public int Value { get { return this.value; } } public Integer(int value) { this.value = value; } } public Integer Add(Integer other) { return new Integer(this.value + other.value); } } 

就像一个int除了它是一个引用类型,但它是不可变的。 我们定义为如此。 我们也可以将它定义为可变的:

 class MutableInteger { private int value; public int Value { get { return this.value; } } public MutableInteger(int value) { this.value = value; } } public MutableInteger Add(MutableInteger other) { this.value = this.value + other.value; return this; } } 

看到?

当我将valueA分配给valueB时,我不明白哪个语言function会复制valueA

它不复制string ,它复制引用。 string s是引用类型。 这意味着string类型的变量是其值为引用的存储位置。 在这种情况下,它们的值是对string实例的引用。 将string类型的变量分配给另一个string类型时,将复制该值。 在这种情况下,该值是一个引用,它由赋值复制。 对于任何引用类型都是如此,不仅仅是string或只是不可变引用类型。

或者,当我将valueA赋值给valueB ,对valueA的引用不会改变,只有当我设置字符串时, valueA才会获得对自身的新引用。

不, valueAvalueB的值指的是string的相同实例。 它们的值是引用,这些值是相等的。 如果你能以某种方式改变* valueA引用的string实例,那么valueAvalueB valueA都会看到这个突变。

由于这是一个实例类型,我不明白为什么这样做。

没有实例类型这样的东西。

基本上, string s是引用类型。 但string是不可变的。 当你改变一个string ,会发生的是你得到一个新字符串的引用,这个字符串是对现有string

 string s = "hello, world!"; string t = s; string u = s.ToUpper(); 

这里, st是变量,其值指的是string的相同实例。 通过调用String.ToUpper不会改变s String.ToUpper 。 相反, s.ToUppers的引用进行了变异,并返回对它在应用变异过程中创建的新string实例的引用。 我们将该引用分配给u

我知道你可以重载,例如,==和!=运算符,但我似乎找不到有关重载=运算符的任何文档。

你不能超载=

*你可以用一些技巧。 别理他们。

首先,您的示例将对任何引用变量起作用,而不仅仅是字符串。

会发生什么:

 string valueA = "FirstValue"; //ValueA is referenced to "FirstValue" string valueB = valueA; //valueB references to what valueA is referenced to which is "FirstValue" valueA = "AnotherValue"; //valueA now references a new value: "AnotherValue" Assert.AreEqual("FirstValue", valueB); // remember that valueB references "FirstValue" 

现在, 不变性是一个不同的概念。 这意味着值本身无法更改。
这将出现在这样的情况:

 string valueA = "FirstValue"; //ValueA is referenced to "FirstValue" string valueB = valueA; //valueB references to what valueA is referenced to which is "FirstValue" valueA.Replace('F','B'); //valueA will now be: "BirstValue" Assert.AreEqual("FirstValue", valueB); // remember that valueB references "FirstValue" 

这是因为String的不变性,valueA不会改变字符串本身……它会创建一个带有更改和引用的新COPY

或者,当我将valueA赋值给valueB时,对valueA的引用不会改变,只有当我设置字符串时,valueA才会获得对自身的新引用。

那是正确的。 由于字符串是不可变的,因此引用相同字符串对象的两个变量没有问题。 当您为其中一个分配新字符串时,它是被替换的引用,而不是字符串对象。

我似乎无法找到有关重载=运算符的任何文档。

这不是由于你方面的任何缺点,这是因为没有办法在C#中重载赋值运算符。

=运算符非常简单,它取右侧的值并分配给左侧的变量。 如果它是引用类型,则该值是引用,因此这是分配的内容。