如果我将一个对象传递给一个方法,为什么我应该使用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关键字,可以有效地将引用传递给引用。在许多方面,这与使用out关键字是相同的,但有一个微小的区别,即不能保证该方法实际会将任何东西赋值给ref'ed形参。

其他回答

如果你想改变对象是什么,传递一个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;
}

这就像在c中传递一个指针给另一个指针一样,在。net中,这将允许你改变原来的T指的是什么,尽管我个人认为,如果你在。net中这样做,你可能有一个设计问题!

你需要区分“通过值传递引用”和“通过引用传递参数/参数”。

我写了一篇相当长的关于这个主题的文章,以避免每次在新闻组上出现这个问题时都要仔细写

将引用类型(例如List<T>)的变量(例如foo)视为持有形式为“object# 24601”的对象标识符。假设语句foo = new List<int> {1,5,7,9};使foo保存“Object #24601”(一个包含四个项的列表)。然后调用foo。Length将向object# 24601请求其长度,它将响应4,因此输入foo。长度等于4。

如果foo被传递给一个方法而没有使用ref,该方法可能会对Object #24601进行更改。作为这些变化的结果,foo。Length可能不再等于4。然而,方法本身将无法更改foo,它将继续保存“object# 24601”。

将foo作为ref参数传递将允许被调用的方法不仅对Object #24601进行更改,而且对foo本身进行更改。该方法可以创建一个新的对象#8675309,并在foo中存储对该对象的引用。如果这样做,foo将不再保存“object# 24601”,而是保存“object# 8675309”。

In practice, reference-type variables don't hold strings of the form "Object #8675309"; they don't even hold anything that can be meaningfully converted into a number. Even though each reference-type variable will hold some bit pattern, there is no fixed relationship between the bit patterns stored in such variables and the objects they identify. There is no way code could extract information from an object or a reference to it, and later determine whether another reference identified the same object, unless the code either held or knew of a reference that identified the original object.

有了ref,你可以写:

static public void DoSomething(ref TestRef t)
{
    t = new TestRef();
}

t将在方法完成后更改。