.NET 字符串和引用类型参数
下面的代码是如何工作的?
public void SomeMethod()
{
StringBuilder sb = new StringBuilder();
AppendFoo(sb);
String foo = sb.ToString(); // foo is "foo"
String s = String.Empty;
AppendBar(s);
String bar = s; // bar is empty
}
public void AppendFoo(StringBuilder x)
{
x.Append("Foo");
}
public void AppendBar(String x)
{
x = x + "Bar";
}
如果 StringBuilder
和 String
都是引用类型,为什么在通过 AppendBar
方法传递字符串对象时不会改变它,而 StringBuilder 对象是将其传递到 AppendFoo 方法时是否发生了变化,因为方法的两个参数都将引用类型作为参数?
How does the following code work?
public void SomeMethod()
{
StringBuilder sb = new StringBuilder();
AppendFoo(sb);
String foo = sb.ToString(); // foo is "foo"
String s = String.Empty;
AppendBar(s);
String bar = s; // bar is empty
}
public void AppendFoo(StringBuilder x)
{
x.Append("Foo");
}
public void AppendBar(String x)
{
x = x + "Bar";
}
If both StringBuilder
and String
are reference types, why is the string object not altered when passing it through the AppendBar
method, whereas the StringBuilder object is altered when passing it into the AppendFoo
method, as the both parameters to the methods are taking reference types as parameters?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
暂时忽略字符串是不可变的事实——这有点转移注意力。重要的一点是:
和
仔细观察它们:第一个作用于
x
引用的对象,更改StringBuilder 的内容
。第二个是更改 x 的值以引用不同的对象(新字符串)。它没有更改现有对象的内容。 (事实上,它不能,因为字符串是不可变的,但无论如何都会应用相同的逻辑。)在方法内更改
x
的值不会改变用于初始化x
的参数值。关键点是区分更改变量的值和更改其引用的对象的内容。一旦你找到了这种差异,剩下的就应该水到渠成了。
在我关于参数传递的文章中阅读有关此内容和参数的更多信息,以及有关引用类型的更多信息与另一篇文章中的值类型的比较。
Ignore the fact that strings are immutable for the moment - it's a bit of a red herring. The important point is the difference between:
and
Look at them closely: the first one is acting on the object that
x
refers to, changing the contents of theStringBuilder
. The second is changing the value ofx
to refer to a different object (a new string). It's not changing the contents of the existing object. (In fact it couldn't because strings are immutable, but the same logic would apply anyway.)Changing the value of
x
within a method doesn't change the value of the argument used to initializex
.The crucial point is to differentiate between changing the value of a variable and changing the contents of the object it refers to. Once you've got that difference, the rest should fall into place.
Read more about this and parameters in my article on parameter passing, and more about reference types vs value types in another article.
字符串是不可变的——一旦创建就无法更改。
appendBar 中发生的情况是:
x= x+"Bar"
创建一个新字符串(具有新值)并将引用 x 设置为它。 (实际实现取决于编译器)
但是调用代码中的引用仍然指向原始字符串对象。
Strings are immutable - once created they cannot be changed.
What happens in appendBar is:
x= x+"Bar"
Creates a new string (with the new value) and sets the reference x to it. (Actual implementation is compiler dependent)
But the reference s in the calling code still points to the original string object.
字符串是引用类型,但在 C# 中它们是不可变的,这意味着一旦分配,它们就永远不会更改其内容。 时,您所做的就是
当您说“创建一个包含 x+"Bar" 的新字符串并将其分配给 x 的本地引用 。因为您没有将字符串作为“ref”参数传递,所以分配给本地引用不会影响函数外部的引用。
Strings are reference types, but in C# they are immutable, meaning once assigned, they never change their contents. All you are doing when you say
is 'create a new string containing x+"Bar" and assign it to the local reference of x. Because you didn't pass the string is as a 'ref' parameter, assigning to the local reference doesn't affect the reference outside the function.
在第一次调用
AppendFoo
中,您通过调用参数的方法成员来更改参数。在第二次调用
AppendBar
中,您为参数分配新值。它不反映原始参数(除非您通过 ref 调用它)例如,如果第一次调用是:
您将得到相同的结果。
很容易认为它与字符串不可变这一事实有关,但实际上与之无关。它只是为参数分配新值,因此它不会更改发送到的原始对象方法。
In the first call,
AppendFoo
, you alter the argument, by calling a method member of it.In the 2nd call,
AppendBar
, you assign new value to the argument. It does not reflect the original argument (unless you call it by ref)For example, if the first call would have been:
You would have gotten the same result.
It is tempting to think it's related to the fact strings are immutable but it has nothing to do with it. It's just an assignment of new value to argument and therefore it does not change the original object sent to the method.
字符串根本不可变并不重要,您在 AppendBar 函数中缺少 ref 参数。
逻辑是相同的,如果你的 AppendFoo 是
它也不起作用......如果你想更改引用的值,你需要将 x var 声明为 ref。
It doesn't matter that string are immutable at all, you are missing a ref parameter in the AppendBar function.
The logic is the same, if your AppendFoo was
it would not work either... if you want to change the value of the reference, you need to declare the x var as ref.
.NET 字符串实际上是一种不可变数据类型,这意味着一旦初始化字符串对象,该字符串对象就永远无法更改。看起来像是修改字符串内容的运算符,实际上是创建新字符串,然后将变量中存储的地址更新为新创建字符串的地址。旧字符串变得不受引用。
因此,在将字符串传递给函数的情况下,例如,当您执行
AppendBar(string x)
时,会发生以下情况:x = x + "Bar"
, .NET 运行时分配足够的内存来存储组合文本。示例中为空的原始文本和“Bar”将被复制到新的字符串实例中。x
被更新为指向新字符串实例的地址。但是,由于s
作为副本传递给AppendBar(string x)
,因此调用方方法中s
的值不会更新为指向新的字符串实例。它仍然存储旧地址,即空字符串地址。因此,在调用该函数后,对s
的引用仍然会产生空字符串。您可以将函数的签名更改为
AppendBar(ref string x)
,以更改传递给函数的字符串。在语句AppendBar(ref s);
之后,s
先是“is”,然后是“Bar”。.NET string is actually an immutable data type, which means that once you initialize a string object, that string object can never change. An operators that looks like modifying the contents of a string, actually creates new string, then updates the address stored in the variable to that of the newly created string. The old string becomes unreferenced.
So in the case of passing a string to a function, your
AppendBar(string x)
for example, what happens is that when you dox = x + "Bar"
, the .NET runtime allocates enough memory to store the combined text. The original text which is empty in your sample and "Bar" are copied into the new string instance.x
is updated to point to the address of the new string instance. However, sinces
is passed to theAppendBar(string x)
as a copy, the value ofs
in your caller method is not updated to point to the new string instance. It's still storing the address of the old one, the empty string one. Therefore, after calling the function, your referencing ofs
still yields the empty string.You can change the signature of the function to
AppendBar(ref string x)
to make the string passed to function altered. After the statementAppendBar(ref s);
,s
"is" then "Bar".