C#中的字符串引用[重复]

Posted

技术标签:

【中文标题】C#中的字符串引用[重复]【英文标题】:String reference in C# [duplicate] 【发布时间】:2021-07-21 12:51:36 【问题描述】:

由于字符串是dotnet中的ref类型,当我们更新变量x时,y也应该有更新? (因为它指的是 x 的值)。下面给出的示例程序,当 x 更新时,y 的值如何不改变?

public void assignment()

    string x= "hello";
    string y=x; // referencing x as string is ref type in .net
    x = x.Replace('h','j');
    Console.WriteLine(x); // gives "jello" output
    Console.WriteLine(y); // gives "hello" output 

【问题讨论】:

不,基本上。改变一个变量的值(不影响其他变量)和改变一个对象的内容是有区别的。见jonskeet.uk/csharp/references.html 和***.com/a/32010236/22656 您在谈论可变与不可变。 String 是不可变的,它始终保持相同的值。字符串也是引用类型,它没有默认分配大小。 @Bizhan:这与不变性无关。即使字符串是可变的,改变一个变量的值也不会改变另一个变量。 (例如,假设我们使用StringBuilder 而不是string,并且有问题的行是x = null; - 这不会使y 为空。) @JonSkeet 我认为它也是关于不变性的,因为例如StringBuilder.Replace 发生变异并返回自身,所以x = x.Replace(...) 也会改变y 中的值。 @Charlieface:这正是我没有在我的示例中使用Replace 的原因。假设string 实际上是可变的,但Replace 的当前行为是返回一个新字符串而不是修改现有字符串。 (例如,也许会有一个 ReplaceInExistingObject 方法会改变它。)这个问题中的行为根本不会改变 【参考方案1】:

您是对的,最初,xy 都引用同一个对象:

       +-----------+
y   -> |   hello   |
       +-----------+
            ^
x   --------+

现在看看这一行:

x = x.Replace('h','j');

会发生以下情况:

    x.Replace 创建一个 new 字符串(将 h 替换为 j)并返回对这个新字符串的引用。

           +-----------+    +------------+
    y   -> |   hello   |    |   jello    |
           +-----------+    +------------+
                ^
    x   --------+
    

    使用x = ...,您可以将x 分配给这个新引用。 y 仍然引用旧字符串。

           +-----------+    +------------+
    y   -> |   hello   |    |   jello    |
           +-----------+    +------------+
                                  ^
    x   --------------------------+
    

那么如何就地修改字符串?你没有。 C# 不支持就地修改字符串。字符串是deliberately designed 作为一个不可变 数据结构。对于可变的类似字符串的数据结构,使用StringBuilder:

var x = new System.Text.StringBuilder("hello");
var y = x;

// note that we did *not* write x = ..., we modified the value in-place
x.Replace('h','j');

// both print "jello"
Console.WriteLine(x);
Console.WriteLine(y);

【讨论】:

【参考方案2】:

这里已经有很好的答案为什么会发生这种情况。 但是,如果您希望两者都打印“jello”,您可以使用 ref 关键字通过引用将 x 分配给 y。

string x = "hello";
ref string y = ref x;
x = x.Replace('h', 'j');
Console.WriteLine(x); // gives "jello" output
Console.WriteLine(y); // gives "jello" output 

更多关于参考本地人here的信息。

【讨论】:

非常好,虽然我个人更喜欢称它为“让 y 成为 x 的别名”,以避免短语“通过引用分配”的歧义。跨度> 【参考方案3】:

返回的字符串是一个新的字符串引用。 关于 string.Replace() MSDN 说:

"此方法不会修改当前实例的值,而是返回一个新字符串,其中所有出现的 oldValue 都替换为 newValue"

https://docs.microsoft.com/en-us/dotnet/api/system.string.replace?view=net-5.0.

正如@Heinzi 所述 - 字符串是不可变的,对字符串执行的大多数操作都会产生新字符串:

“字符串对象是不可变的:它们在创建后无法更改。所有看似修改字符串的 String 方法和 C# 运算符实际上都在新的字符串对象中返回结果”

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#:~:text=String%20objects%20are%20immutable%3A%20they,in%20a%20new%20string%20object.

干杯!

【讨论】:

以上是关于C#中的字符串引用[重复]的主要内容,如果未能解决你的问题,请参考以下文章

C#中的字符串枚举[重复]

无论c#中的字符是啥,如何根据每三个字符分割一个字符串[重复]

char []到C#中的字符串[重复]

C#中的特殊字符打印[重复]

从 C# 中的 WebSocket 流中读取整个字符串 [重复]

显示列表中的重复项 c#