“ref&quot有什么用?对于c#中的引用类型变量?

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

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


举个例子:

var x = new Foo();

以下两种有什么区别?

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

而且

void Bar(ref Foo y) {
y.Name = "2";
}
46129 次浏览

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

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]);

你可以使用y来改变foo指向的对象:

Foo foo = new Foo("1");


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


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

它允许您修改传入的引用。如。

void Bar()
{
var y = new Foo();
Baz(ref y);
}


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


// Overwrite the reference
y = new Foo();
}

如果你不关心传入的引用,你也可以使用:

void Bar()
{
var y = new Foo();
Baz(out y);
}


void Baz(out Foo y)
{
// Return a new reference
y = new Foo();
}

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

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

另一组代码

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;
}
}

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

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

引用参数不通过 类中使用的变量的值 函数成员调用-它们使用 变量本身。而不是 为创建新的存储位置 函数成员中的变量 声明,相同的存储位置 是用的,那么变量的值是多少呢 在函数成员和值中 的引用参数 保持一致。需要参考参数 属性中的ref修饰符 声明和调用 意思是当你

这里解释得很好: http://msdn.microsoft.com/en-us/library/s6938f28.aspx < / p >

文章摘要:

引用类型的变量不直接包含它的数据;它 包含对其数据的引用。当您传递引用类型时 参数的值,则可以更改所指向的数据 引用,例如类成员的值。然而,你 不能更改引用本身的值;也就是说,你不能 使用相同的引用为新类分配内存并拥有它 在块外持久化。方法传递参数

. Ref or out关键字

方法中的参数似乎总是传递一个副本,问题是一个什么副本。复制是由对象的复制构造函数完成的,因为c#中所有变量都是object,我相信这是所有变量的情况。变量(对象)就像居住在某些地址的人。我们要么改变住在这些地址的人,要么在电话簿中创建更多对住在这些地址的人的引用(做浅拷贝)。因此,多个标识符可以引用同一个地址。引用类型需要更多的空间,因此与直接通过箭头连接到堆栈中的标识符的值类型不同,它们具有堆中另一个地址的值(可以驻留的空间更大)。这个空间需要从堆中取出。

< p >值类型: 标识符(包含值=堆叠值的地址)---->值类型

< p >引用类型: 标识符(包含值=堆栈值的地址)---->(包含值=堆值的地址)---->堆值(通常包含到其他值的地址),想象更多的箭头指向数组[0],数组[1],数组[2]

更改值的唯一方法是遵循箭头。如果一个箭头丢失/改变了该值不可达的方式。

除了现有的答案:

当使用refout时,没有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有什么用。 引用变量(405)是有效的,直到没有新的内存分配给在方法中传递的引用变量。< / p > 一旦分配了新的内存(410),那么这个对象(408)上的值变化将不会反映在所有地方。 裁判来了。Ref是引用的引用,所以每当分配新的内存时,它就会知道,因为它指向那个位置,因此这个值可以被每个人共享。你可以看到更清晰的图像。

参考变量Ref in Reference Variable