C#中的字符串赋值

Ste*_*uts 20 c# string heap reference

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

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

string valueA = "FirstValue";
string valueB = valueA;
valueA = "AnotherValue";

Assert.AreEqual("FirstValue", valueB); // Passes
Run Code Online (Sandbox Code Playgroud)

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

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

jas*_*son 15

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

它不是语言功能.这是课程定义的方式.

例如,

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

就像是一个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;
    } 
}
Run Code Online (Sandbox Code Playgroud)

看到?

我不明白valueA当我分配它时,什么语言功能复制valueB.

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

或者,valueA当我指定它时,引用不会改变valueB,只有valueA在设置字符串时才会获得对自身的新引用.

不,它的值valueAvalueB引用相同的实例string.它们的值是引用,这些值是相等的.如果你能以某种方式发生变异*实例string提到了valueA,两者的referrent valueAvalueB会看到这种突变.

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

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

基本上,strings是引用类型.但是string是不可改变的.当你改变a时string,会发生的是你得到一个新字符串的引用,该字符串是已经存在的变异的结果string.

string s = "hello, world!";
string t = s;
string u = s.ToUpper();
Run Code Online (Sandbox Code Playgroud)

在这里,s并且t是变量,其值是指的同一个实例string.的referrent s不被调用突变String.ToUpper.相反,s.ToUppers引用进行变异并返回string对它在应用变异过程中创建的新实例的引用.我们将该引用分配给u.

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

你不能超载=.

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


Yoc*_*mer 6

首先,您的示例将对任何引用变量执行相同的操作,而不仅仅是字符串.

会发生什么:

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"
Run Code Online (Sandbox Code Playgroud)

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

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"
Run Code Online (Sandbox Code Playgroud)

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

  • 虽然你的答案很好地解释了第一部分,但你对不变性的看法并不是很正确.`valueA.Replace('F','B')`将使`valueA`与"FirstValue"保持一致,这就是它们的不可变性. (3认同)
  • string.Replace(this string,char,char)字面上返回一个新字符串作为返回值.我不确定上面的第二个例子是否证明了不变性,因为断言中没有使用返回值.请澄清.谢谢. (2认同)