Col*_*son 114 .net string function parameter-passing
当我传递string给一个函数时,是一个指向传递给字符串内容的指针,还是整个字符串传递给堆栈上的函数就像struct是?
Jus*_*gan 262
要回答您的问题,请考虑以下代码:
void Main()
{
string strMain = "main";
DoSomething(strMain);
Console.Write(strMain); // What gets printed?
}
void DoSomething(string strLocal)
{
strLocal = "local";
}
Run Code Online (Sandbox Code Playgroud)
为了预测这里会发生什么,并了解其原因,您需要了解三件事.
strMain也不通过引用传递.它是一个引用类型,但引用是按值传递的.这是一个棘手的区别,但它是一个至关重要的区别.每当你传递一个没有ref关键字的参数(不计算out参数)时,你就按值传递了一些东西.但是,这是什么意思?
C#中有两组数据类型:引用类型和值类型.在C#中还有两种传递参数的方法:按引用和按值传递.这听起来一样,容易混淆.它们不是同一件事!
如果传递任何类型的参数,并且不使用该ref关键字,那么您已按值传递它.如果你按值传递它,你真正传递的是副本.但是如果参数是引用类型,那么你复制的东西就是引用,而不是它指向的东西.
这是我们Main方法的第一行:
string strMain = "main";
Run Code Online (Sandbox Code Playgroud)
实际上我们在这一行上创建了两件事:一个字符串,其值main存储在某个地方的内存中,一个名为strMain指向它的引用变量.
DoSomething(strMain);
Run Code Online (Sandbox Code Playgroud)
现在我们将该引用传递给DoSomething.我们按价值通过了它,这意味着我们制作了一份副本.但它是一个引用类型,因此这意味着我们复制了引用,而不是字符串本身.现在我们有两个引用,每个引用都指向内存中的相同值.
这是DoSomething方法的顶部:
void DoSomething(string strLocal)
Run Code Online (Sandbox Code Playgroud)
ref像往常一样没有关键字.所以strLocal不是strMain,但他们都指向同一个地方.如果我们"改变" strLocal,就像这样......
strLocal = "local";
Run Code Online (Sandbox Code Playgroud)
......我们本身没有改变储值.我们重新指出了这个参考.我们接受了所谓的参考,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"
Run Code Online (Sandbox Code Playgroud)
让我们改变场景一秒钟.想象一下,我们不使用字符串,而是使用一些可变引用类型,就像您创建的类一样.
class MutableThing
{
public int ChangeMe { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果您按照objLocal它指向的对象的引用,您可以更改其属性:
void DoSomething(MutableThing objLocal)
{
objLocal.ChangeMe = 0;
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
......字符串是不可变的!没有ChangeMe可设置的属性.你不能strLocal[3] = 'H';像C风格的char数组那样做; 你必须改为构造一个全新的字符串.改变的唯一方法strLocal是将引用指向另一个字符串,这意味着你所做的任何事情都strLocal无法影响strMain.该值是不可变的,引用是副本.
因此,即使字符串是引用类型,通过值传递它们意味着被调用者中发生的任何事情都不会影响调用者中的字符串.但由于它们是引用类型,因此当您想要传递它时,不必将整个字符串复制到内存中.
das*_*ght 23
C#中的字符串是不可变的引用对象.这意味着对它们的引用会传递(按值),一旦创建了一个字符串,就无法修改它.生成字符串的修改版本(子字符串,修剪版本等)的方法会创建原始字符串的修改副本.
Eni*_*ity 10
字符串是特殊情况.每个实例都是不可变的.当您更改字符串的值时,您将在内存中分配新字符串.
因此,只有引用被传递给您的函数,但是当编辑该字符串时,它将成为一个新实例,并且不会修改旧实例.