传递引用;然而,从技术上讲,这不是passed by reference.这是一个微妙的,但非常重要的区别.考虑下面的代码:
void DoSomething(string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomething(strMain);
Console.WriteLine(strMain); // What gets printed?
}
要了解这里发生的事情,您需要了解三件事:
strMain
也不是通过引用传递的.它是reference type,,但参考本身是passed by value.任何时候,当你传递一个没有ref
关键字的参数(不包括out
个参数)时,你就按值传递了一些东西.那一定意味着你...通过值传递引用.因为它是引用类型,所以只有引用被复制到堆栈中.但这意味着什么?
C#变量可以是reference types或value types.C#参数为passed by reference或passed by value.术语在这里是个问题;这些听起来是一样的,但事实并非如此.
如果您传递了任何类型的参数,并且没有使用ref
关键字,那么您是按值传递的.如果你通过值传递,你真正传递的是一个副本.但是如果参数是引用类型,那么你复制的是reference,,而不是它指向的任何东西.
下面是Main
方法的第一行:
string strMain = "main";
我们在这行中创建了两个东西:一个值为main
的字符串存储在内存中的某个地方,一个名为strMain
的引用变量指向它.
DoSomething(strMain);
现在我们将该引用传递给DoSomething
.我们是按值传递的,所以这意味着我们复制了一个副本.它是引用类型,所以这意味着我们复制了引用,而不是字符串本身.现在我们有两个引用,每个引用都指向内存中的相同值.
下面是DoSomething
种方法中的前几种:
void DoSomething(string strLocal)
没有ref
关键字,所以strLocal
和strMain
是指向相同值的两个不同引用.如果我们重新分配strLocal
...
strLocal = "local";
...我们没有改变存储值;我们把这个名为strLocal
的参考号对准了一个全新的字符串.当我们这样做时,strMain
会发生什么?Nothing. It's still pointing at the old string.
string strMain = "main"; // Store a string, create a reference to it
DoSomething(strMain); // Reference gets copied, copy gets re-pointed
Console.WriteLine(strMain); // The original string is still "main"
让我们改变一下情景.假设我们不使用字符串,而是使用一些可变引用类型,比如您创建的类.
class MutableThing
{
public int ChangeMe { get; set; }
}
如果对其指向的对象的引用objLocal
设置为follow,则可以更改其属性:
void DoSomething(MutableThing objLocal)
{
objLocal.ChangeMe = 0;
}
内存中仍然只有一个MutableThing
,复制的引用和原始引用仍然指向它.The properties of the MutableThing
itself have changed:
void Main()
{
var objMain = new MutableThing();
objMain.ChangeMe = 5;
Console.WriteLine(objMain.ChangeMe); // it's 5 on objMain
DoSomething(objMain); // now it's 0 on objLocal
Console.WriteLine(objMain.ChangeMe); // it's also 0 on objMain
}
啊,但是字符串是不可变的!没有要设置的ChangeMe
属性.你不能像使用C-style char
数组那样在C中执行strLocal[3] = 'H'
;你必须构造一个全新的字符串.更改strLocal
的唯一方法是将引用指向另一个字符串,这意味着对strLocal
所做的任何操作都不会影响strMain
.值是不可变的,引用是副本.
为了证明两者之间存在差异,下面是发生的事情
void DoSomethingByReference(ref string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomethingByReference(ref strMain);
Console.WriteLine(strMain); // Prints "local"
}
这一次,Main
中的字符串确实发生了更改,因为您传递了引用,而没有在堆栈上复制它.
因此,即使字符串是引用类型,通过值传递它们意味着被调用方中发生的任何事情都不会影响调用方中的字符串.但由于它们有are个引用类型,所以在传递字符串时,不必复制内存中的整个字符串.