如果我将一个对象传递给一个方法,为什么我应该使用ref关键字?这难道不是默认的行为吗?
例如:
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t.Something = "Bar";
}
}
public class TestRef
{
public string Something { get; set; }
}
输出是“Bar”,这意味着对象作为引用传递。
如果你想改变对象是什么,传递一个ref:
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);
void DoSomething(ref TestRef t)
{
t = new TestRef();
t.Something = "Not just a changed t, but a completely different TestRef object";
}
调用DoSomething之后,t并不指向原来的新TestRef,而是指向一个完全不同的对象。
如果你想改变一个不可变对象的值,比如一个字符串,这可能也很有用。一旦创建了字符串,就不能更改它的值。但是通过使用ref,您可以创建一个函数,将字符串更改为另一个具有不同值的字符串。
除非需要,否则使用ref不是一个好主意。使用ref使方法可以自由地将参数更改为其他内容,因此需要对方法的调用者进行编码,以确保他们能够处理这种可能性。
同样,当参数类型是对象时,对象变量总是作为对象的引用。这意味着当使用ref关键字时,您获得了对引用的引用。这允许您按照上面给出的示例进行操作。但是,当形参类型是一个基元值(例如int)时,那么如果这个形参在方法中被赋值,传入的实参值将在方法返回后被更改:
int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10
void Change(ref int x)
{
x = 5;
}
void WillNotChange(int x)
{
x = 10;
}
在. net中,当您将任何参数传递给方法时,将创建一个副本。在值类型中意味着您对值所做的任何修改都在方法范围内,并且在退出方法时丢失。
当传递一个引用类型时,也会生成一个副本,但它是一个引用的副本,也就是说,现在内存中有两个对同一个对象的引用。因此,如果你使用引用来修改对象,它就会被修改。但是如果您修改了引用本身——我们必须记住它是一个副本——那么任何更改也会在退出方法时丢失。
正如人们之前所说,赋值是对引用的修改,因此丢失了:
public void Method1(object obj) {
obj = new Object();
}
public void Method2(object obj) {
obj = _privateObject;
}
上述方法不修改原始对象。
对你的例子做一点修改
using System;
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t = new TestRef();
t.Something = "Bar";
}
}
public class TestRef
{
private string s;
public string Something
{
get {return s;}
set { s = value; }
}
}