我知道,如果我传递一个值类型(int, struct等)作为参数(没有ref关键字),该变量的副本将传递给方法,但如果我使用ref关键字,则传递对该变量的引用,而不是一个新变量。

但是对于引用类型,就像类一样,即使没有ref关键字,也会将引用传递给方法,而不是副本。那么ref关键字与reference-types有什么用呢?


举个例子:

var x = new Foo();

以下两种有什么区别?

void Bar(Foo y) {
    y.Name = "2";
}

and

void Bar(ref Foo y) {
    y.Name = "2";
}

当前回答

除了现有的答案:

正如你所要求的2种方法的差异:使用ref或out时没有co(ntra)方差:

class Foo { }
class FooBar : Foo { }

static void Bar(Foo foo) { }
static void Bar(ref Foo foo) { foo = new Foo(); }

void Main()
{
    Foo foo = null;
    Bar(foo);           // OK
    Bar(ref foo);       // OK

    FooBar fooBar = null;
    Bar(fooBar);        // OK (covariance)
    Bar(ref fooBar);    // compile time error
}

其他回答

当您传递带有ref关键字的引用类型时,您逐个引用传递引用,并且您调用的方法可以为参数分配一个新值。该更改将传播到调用作用域。如果没有ref,引用是按值传递的,这不会发生。

c#也有'out'关键字,它很像ref,除了使用'ref',参数必须在调用方法之前初始化,使用'out'你必须在接收方法中赋值。

在某些情况下,你想修改实际的引用,而不是所指向的对象:

void Swap<T>(ref T x, ref T y) {
    T t = x;
    x = y;
    y = t;
}

var test = new[] { "0", "1" };
Swap(ref test[0], ref test[1]);

Jon Skeet写了一篇关于c#参数传递的很棒的文章。它清楚地详细描述了按值、按引用(ref)和按输出(out)传递参数的确切行为和用法。

下面是该页关于ref参数的重要引用:

Reference parameters don't pass the values of the variables used in the function member invocation - they use the variables themselves. Rather than creating a new storage location for the variable in the function member declaration, the same storage location is used, so the value of the variable in the function member and the value of the reference parameter will always be the same. Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference.

另一组代码

class O
{
    public int prop = 0;
}

class Program
{
    static void Main(string[] args)
    {
        O o1 = new O();
        o1.prop = 1;

        O o2 = new O();
        o2.prop = 2;

        o1modifier(o1);
        o2modifier(ref o2);

        Console.WriteLine("1 : " + o1.prop.ToString());
        Console.WriteLine("2 : " + o2.prop.ToString());
        Console.ReadLine();
    }

    static void o1modifier(O o)
    {
        o = new O();
        o.prop = 3;
    }

    static void o2modifier(ref O o)
    {
        o = new O();
        o.prop = 4;
    }
}

你可以用y来改变foo指向的东西:

Foo foo = new Foo("1");

void Bar(ref Foo y)
{
    y = new Foo("2");
}

Bar(ref foo);
// foo.Name == "2"