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
才会获得对自身的新引用。
不, valueA
和valueB
的值指的是string
的相同实例。 它们的值是引用,这些值是相等的。 如果你能以某种方式改变* valueA
引用的string
实例,那么valueA
和valueB
valueA
都会看到这个突变。
由于这是一个实例类型,我不明白为什么这样做。
没有实例类型这样的东西。
基本上, string
s是引用类型。 但string
是不可变的。 当你改变一个string
,会发生的是你得到一个新字符串的引用,这个字符串是对现有string
。
string s = "hello, world!"; string t = s; string u = s.ToUpper();
这里, s
和t
是变量,其值指的是string
的相同实例。 通过调用String.ToUpper
不会改变s
String.ToUpper
。 相反, s.ToUpper
对s
的引用进行了变异,并返回对它在应用变异过程中创建的新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#中重载赋值运算符。
=
运算符非常简单,它取右侧的值并分配给左侧的变量。 如果它是引用类型,则该值是引用,因此这是分配的内容。