【问题标题】:String reference in C# [duplicate]C#中的字符串引用[重复]
【发布时间】: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.htmlstackoverflow.com/a/32010236/22656
  • 您在谈论可变与不可变。 String 是不可变的,它始终保持相同的值。字符串也是引用类型,它没有默认分配大小。
  • @Bizhan:这与不变性无关。即使字符串是可变的,改变一个变量的值也不会改变另一个变量。 (例如,假设我们使用StringBuilder 而不是string,并且有问题的行是x = null; - 这不会使y 为空。)
  • @JonSkeet 我认为它也是关于不变性的,因为例如StringBuilder.Replace 发生变异并返回自身,所以x = x.Replace(...) 也会改变y 中的值。
  • @Charlieface:这正是我没有在我的示例中使用Replace 的原因。假设string 实际上是可变的,但Replace 的当前行为是返回一个新字符串而不是修改现有字符串。 (例如,也许会有一个 ReplaceInExistingObject 方法会改变它。)这个问题中的行为根本不会改变

标签: c# .net string


【解决方案1】:

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

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

现在看看这一行:

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

会发生以下情况:

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

           +-----------+    +------------+
    y   -> |   hello   |    |   jello    |
           +-----------+    +------------+
                ^
    x   --------+
    
  2. 使用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.

    干杯!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-31
      • 1970-01-01
      • 2011-06-08
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      • 2019-06-03
      • 2019-04-10
      相关资源
      最近更新 更多