.NET 中的字符串是如何传递的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10792603/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How are strings passed in .NET?
提问by Cole Johnson
When I pass a stringto a function, is a pointer to the string's contents passed, or is the entire string passed to the function on the stack like a structwould be?
当我将 a 传递string给函数时,是传递了指向字符串内容的指针,还是像 a 一样struct将整个字符串传递给堆栈上的函数?
回答by Justin Morgan
To answer your question, consider the following code:
要回答您的问题,请考虑以下代码:
void Main()
{
string strMain = "main";
DoSomething(strMain);
Console.Write(strMain); // What gets printed?
}
void DoSomething(string strLocal)
{
strLocal = "local";
}
There are three things you need to know in order to predict what will happen here, and to understand why it does.
为了预测这里会发生什么,并理解为什么会发生,你需要知道三件事。
- Strings are reference types in C#. But this is only part of the picture.
- They are also immutable, so any time you do something that looks like you're changing the string, you aren't. A completely new string gets created, the reference is pointed at it, and the old one gets thrown away.
- Even though strings are reference types,
strMainisn't passed by reference. It's a reference type,but the reference is being passed by value. This is a tricky distinction, but it's a crucial one. Any time you pass a parameter without therefkeyword (not countingoutparameters), you've passed something by value.
- 字符串是 C# 中的引用类型。但这只是图片的一部分。
- 它们也是不可变的,所以每当你做一些看起来像是在改变字符串的事情时,你就不是。一个全新的字符串被创建,引用指向它,旧的被丢弃。
- 即使字符串是引用类型,
strMain也不会通过引用传递。它是一个引用类型,但引用是通过 value 传递的。这是一个棘手的区别,但它是一个关键的区别。任何时候你传递一个没有ref关键字的参数(不计算out参数),你已经通过值传递了一些东西。
But what does that mean?
但是,这是什么意思?
Passing reference types by value: You're already doing it
按值传递引用类型:您已经在做
There are two groups of data types in C#: reference typesand value types. There are also two ways to pass parameters in C#: by referenceand by value. These sound the same and are easily confused. They are NOT the same thing!
C#中有两组数据类型:引用类型和值类型。在 C# 中还有两种传递参数的方式:通过引用和通过值。这些听起来相同,很容易混淆。它们不是同一件事!
If you pass a parameter of ANY type, and you don't use the refkeyword, then you've passed it by value. If you've passed it by value, what you really passed was a copy. But if the parameter was a reference type, then the thing you copied was the reference,not whatever it was pointing at.
如果您传递任何类型的参数,并且不使用ref关键字,那么您已经按值传递了它。如果您按值传递了它,那么您真正传递的是一个副本。但是如果参数是引用类型,那么你复制的就是引用,而不是它指向的任何东西。
Here's the first line of our Mainmethod:
这是我们Main方法的第一行:
string strMain = "main";
There are actually two things we've created on this line: a string with the value mainstored off in memory somewhere, and a reference variable called strMainpointing to it.
我们在这一行实际上创建了两件事:一个字符串,其值main存储在内存中的某处,以及一个称为strMain指向它的引用变量。
DoSomething(strMain);
Now we pass that reference to DoSomething. We've passed it by value, so that means we made a copy. But it's a reference type, so that means we copied the reference, not the string itself. Now we have two references that each point to the same value in memory.
现在我们将该引用传递给DoSomething. 我们已经按值传递了它,所以这意味着我们制作了一个副本。但它是一个引用类型,所以这意味着我们复制了引用,而不是字符串本身。现在我们有两个引用,每个引用都指向内存中的相同值。
Inside the callee
被调用者内部
Here's the top of the DoSomethingmethod:
这是该DoSomething方法的顶部:
void DoSomething(string strLocal)
No refkeyword, as usual. So strLocalisn't strMain, but they both point to the same place. If we "change" strLocal, like this...
没有ref关键字,像往常一样。所以strLocal不是strMain,但它们都指向同一个地方。如果我们“改变” strLocal,像这样......
strLocal = "local";
...we haven't changedthe stored value, per se. We've re-pointed the reference. We took the reference called strLocaland aimed it at a brand new string. What happens to strMainwhen we do that? Nothing. It's still pointing at the old string!
...我们没有改变存储值本身。我们重新指出了参考。我们将调用的引用strLocal指向一个全新的字符串。strMain当我们这样做时会发生什么?没有。它仍然指向旧字符串!
string strMain = "main"; //Store a string, create a reference to it
DoSomething(strMain); //Reference gets copied, copy gets re-pointed
Console.Write(strMain); //The original string is still "main"
Immutability is important
不变性很重要
Let's change the scenario for a second. Imagine we aren't working with strings, but some mutable reference type, like a class you've created.
让我们改变一下场景。想象一下,我们处理的不是字符串,而是一些可变引用类型,比如您创建的类。
class MutableThing
{
public int ChangeMe { get; set; }
}
If you followthe reference objLocalto the object it points to, you can change its properties:
如果遵循objLocal对它指向的对象的引用,则可以更改其属性:
void DoSomething(MutableThing objLocal)
{
objLocal.ChangeMe = 0;
}
There's still only one MutableThingin memory, and both the copied reference and the original reference still point to it. The properties of the MutableThingitself have changed:
MutableThing内存中仍然只有一个,并且复制的引用和原始引用仍然指向它。本身的属性发生了MutableThing变化:
void Main()
{
var objMain = new MutableThing();
objMain.ChangeMe = 5;
Console.Write(objMain.ChangeMe); //it's 5 on objMain
DoSomething(objMain); //now it's 0 on objLocal
Console.Write(objMain.ChangeMe); //it's also 0 on objMain
}
Ah, but...
啊,可是……
...strings are immutable! There's no ChangeMeproperty to set. You can't do strLocal[3] = 'H';like you could with a C-style char array; you have to construct a whole new string instead. The only way to change strLocalis to point the reference at another string, and that means nothing you do to strLocalcan affect strMain. The value is immutable, and the reference is a copy.
...字符串是不可变的!没有ChangeMe要设置的属性。你不能strLocal[3] = 'H';像使用 C 风格的字符数组那样做;你必须构造一个全新的字符串。更改的唯一方法strLocal是将引用指向另一个字符串,这意味着您所做的任何事情都不会strLocal影响strMain. 值是不可变的,引用是副本。
So even though strings are reference types, passing them by value means whatever goes on in the callee won't affect the string in the caller. But since they arereference types, you don't have to copy the entire string in memory when you want to pass it around.
因此,即使字符串是引用类型,通过值传递它们也意味着被调用者中发生的任何事情都不会影响调用者中的字符串。但是因为它们是引用类型,所以当你想要传递它时,你不必在内存中复制整个字符串。
Further resources:
更多资源:
- Here is the best article I've read on the difference between reference types and value types in C#, and why a reference type isn't the same as a reference-passed parameter.
- As usual, Eric Lippert also has several excellent blog posts on the subject.
- He has some great stuff on immutability, too.
- 这是我读过的关于C# 中引用类型和值类型之间的区别以及引用类型与引用传递参数不同的最佳文章。
- 像往常一样,Eric Lippert 也有几篇关于这个主题的优秀博客文章。
- 他也有一些关于不变性的好东西。
回答by dasblinkenlight
Strings in C# are immutable reference objects. This means that references to them are passed around (by value), and once a string is created, you cannot modify it. Methods that produce modified versions of the string (substrings, trimmed versions, etc.) create modified copiesof the original string.
C# 中的字符串是不可变的引用对象。这意味着对它们的引用是(按值)传递的,并且一旦创建了字符串,就无法修改它。生成字符串修改版本(子字符串、修剪版本等)的方法创建原始字符串的修改副本。
回答by Enigmativity
Strings are special cases. Each instance is immutable. When you change the value of a string you are allocating a new string in memory.
字符串是特殊情况。每个实例都是不可变的。当您更改字符串的值时,您正在内存中分配一个新字符串。
So only the reference is passed to your function, but when the string is edited it becomes a new instance and doesn't modify the old instance.
所以只有引用被传递给你的函数,但是当字符串被编辑时,它变成了一个新实例并且不会修改旧实例。

