【问题标题】:C# String reference type passed as copy? [duplicate]C#字符串引用类型作为副本传递? [复制]
【发布时间】:2014-01-15 20:49:34
【问题描述】:

我对 C#“字符串”引用类型有这个疑问。

以下代码:

string s = "lana del rey" 
string d = s;
s = "elvis presley";
Console.Writeline(d);

为什么输出不是“elvis presley”?如果 d 指向 s 的相同内存位置?

你能解释一下吗?

对我最初的问题的更详细解释:

你所有的答案都非常有用。 这个问题来自这个常见的代码示例,该示例经常用于解释值类型和引用类型之间的区别:

class Rectangle
{
    public double Length { get; set; }
}

struct Point 
{
    public double X, Y;
}

Point p1 = new Point();
p1.X = 10;
p1.Y = 20;
Point p2 = p1;
p2.X = 100;
Console.WriteLine(“p1.X = {0}”, p1.X);

Rectangle rect1 = new Rectangle
{ Length = 10.0, Width = 20.0 };
Rectangle rect2 = rect1;
rect2.Length = 100.0;
Console.WriteLine(“rect1.Length = {0}”,rect1.Length);

在这种情况下,第二个 Console.WriteLine 语句将输出:“rect1.Length = 100”

在这种情况下,类是引用类型,结构是值类型。如何使用字符串演示相同的引用类型行为?

提前致谢。

【问题讨论】:

  • 几分钟前你问了同样的问题,然后删除了你的问题。 “相关”链接对您没有帮助吗?
  • 假设您改为使用int x = 1; int y = x; x = 2; Console.WriteLine(y);,您认为y1 还是2int y = x 并不意味着“y 现在是 x 的别名”。这意味着“y 的当前值更改为x 的当前值”。他们之间没有形成永久的关系。您的sd 也是如此。
  • @EricLippert 我认为他将引用与指针混淆了,正如 zerkms 所提到的那样。
  • 如果您有新问题,那么您应该提出新问题,而不是将新问题编辑到现有(并且已经回答)的问题中。
  • 感谢您的所有反馈@Servy

标签: c# reference-type


【解决方案1】:

它与可变性无关

string s = "lana del rey" 
string d = s;

这里有两个变量sd 引用内存中的同一个对象。

s = "elvis presley";

在语句的右侧部分,新对象被分配并使用"elvis presley" 初始化并分配给s。所以现在s 指的是另一个对象。虽然我们没有更改 d 参考值 - 它继续像原来一样引用 "lana del rey"

现在现实生活中的类比:

有 2 个人(AB)用手指指向远处的建筑物。它们彼此独立,甚至看不到另一个指向的东西。然后A 决定开始指向另一个建筑物。只要它们没有相互连接 - 现在A 指向另一座建筑物,而B 继续指向原来的建筑物(因为没有人要求他们停止这样做)

PS:您可能混淆的是指针和引用背后的概念。不确定在这里解释是否有意义,因为您可能会更加困惑。但现在至少你可以用谷歌搜索相应的关键字了。

【讨论】:

  • 从问题的措辞和性质看来,作者理解s 被设置为d 的引用。他不明白的是"elvis presley" 是在创建一个新的string 实例,而不是设置s 引用的实例的值。这就是为什么string 不变性在这么多答案中被提出:说明为什么要创建一个新的string 实例。
  • @crush:我看不出它是如何相关的 - 两个字符串都没有被修改甚至试图:-S
  • @crush:可变引用类型表现出相同的行为,不是吗?键入“x = y”,其中 x 是引用类型(可变或不可变)绝不意味着“修改 x 引用的对象”。
  • 在我看来,作者认为s = "elvis presley" 正在修改使用string s = "lana del rey"; 创建的string 实例。是的,可变引用类型表现出相同的行为。但是作者不明白正在创建一个新的参考。他认为他只是在设置现有参考的值。这就是我至少在阅读这个问题的设置方式时得出的结论。从他的示例代码中可以明显看出,他知道s = d 正在将这两个引用相互设置。
  • @crush: "但是作者不明白正在创建一个新的引用" --- 并且创建一个新实例仍然与可变性无关。
【解决方案2】:

C# 中的字符串是不可变的;这意味着他们无法改变。当您说s = "elvis presley" 时,您正在创建一个新字符串并将其引用分配给s;这不会影响保存到d 的引用,它仍然指向原始字符串。

【讨论】:

  • 即使对于可变类型,行为也是一样的。 s 是引用,而不是指针。
  • 那么String就像是引用类型的一个例外?
  • @AlbertoMontellano 不。有很多很多不可变的引用类型(您可以根据需要制作更多),它们一点也不例外。
  • @AlbertoMontellano 不是真的(它是一种特殊的引用类型,但不是你的意思)。每当您分配给引用类型的变量时,您只是在更改变量引用的对象。您没有修改原始对象。原始对象仍然存在,其他变量可能会引用它(如果不存在,则该对象有资格进行垃圾回收)。
【解决方案3】:

字符串是不可变的。 s = "elvis presley" 实际上是创建一个新的string 并将它的引用分配给变量s。虽然变量d 仍然引用第一个string "lana del rey"。

【讨论】:

  • 在这种情况下,String 表现为值类型?创建值的副本?
  • @AlbertoMontellano 不,它不像值类型,它像引用类型,因为它就是这样。您不是在创建值的副本,而是在创建 reference 的副本。
【解决方案4】:

让我们逐行看你的代码

string s = "lana del rey";

通过这一行,您创建了一个由s 引用的字符串对象lana del rey

string d = s;

通过这一行,您创建了一个名为 d 的引用,它通过 s 引用了内存中的相同对象(在本例中为 lana del rey

s = "elvis presley";

通过这一行,您创建了一个新的字符串对象elvis presley 并由s 引用(s 不再引用lana del rey

Console.Writeline(d);

由于d 仍然引用lana del rey,它打印lana del rey

【讨论】:

    【解决方案5】:

    字符串的处理方式与常规引用类型不同,这基本上是编译器所做的:

    string s = new String("lana del rey");
    string d = new String(s);
    s = new String("elvis presley");
    Console.Writeline(d);
    

    该点是一个“字符串引用”,指向 s 的字符串 VALUE。每当创建和引用一个新字符串时,它都是一个新字符串,并且对原始值的任何“引用”仍然完好无损。

    【讨论】:

    • 我的观点是一个字符串引用指向s的字符串VALUE。每当创建和引用一个新字符串时,它就是一个新字符串,并且对原始值的任何“引用”仍然完好无损。
    • 然而这一点实际上不在你的答案中。最好明确一点。我怀疑具有 OP 技能水平的人会从看到该代码中推断出这一点。
    • 归结为每个字符串赋值都是一个新字符串,否则你会如何解释?
    • 我只是想在这里提出一些观点......我将编辑我的答案。 =)
    • 或多或少与您在第一条评论中所做的方式相同。我只是说评论应该在你的回答中,而不是评论。
    【解决方案6】:

    来自 Microsoft .NET Framework 2.0 Application Development Foundation 70 536 书:

    "因为引用类型代表的是数据的地址而不是数据本身, 将一个引用变量分配给另一个引用变量不会复制数据。相反,分配 对另一个实例的引用变量只会创建引用的第二个副本, 它指的是堆上与原始变量相同的内存位置。”

    然后我想:

    string s = "lana del rey"; // (creates a reference to the memory location X)
    string d = s; // (creates a copy of the reference to the same memory location X)
    d = "elvis presley"; // (creates a new reference to the new memory location Y)
    

    【讨论】:

      猜你喜欢
      • 2011-08-16
      • 2016-03-10
      • 2014-06-22
      • 2010-11-08
      • 2014-08-11
      • 2017-07-25
      • 2016-07-05
      • 1970-01-01
      • 2012-12-01
      相关资源
      最近更新 更多