在C#中引用types的variables有什么用“ref”?

我明白,如果我传递一个值types( intstruct等)作为参数(不带ref关键字),该variables的副本传递给该方法,但如果我使用ref关键字引用variables被传递,而不是一个新的。

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


举个例子:

 var x = new Foo(); 

以下是什么区别?

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

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

你可以改变什么foo指向使用y

 Foo foo = new Foo("1"); void Bar(ref Foo y) { y = new Foo("2"); } Bar(ref foo); // foo.Name == "2" 

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

 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#中写了一篇关于parameter passing的文章 。 通过参考( ref )和输出( out ),它清楚地详细说明了按值传递参数的确切行为和用法。

以下是关于ref参数的那个页面的一个重要的引用:

引用参数不传递函数成员调用中使用的variables的值 – 它们使用variables本身。 不是在函数成员声明中为variables创build一个新的存储位置,而是使用相同的存储位置,所以函数成员中的variables值和引用参数的值将始终相同。 引用参数需要ref修饰符作为声明和调用的一部分 – 这意味着当您通过引用传递某个东西时,它总是很清晰。

在这里很好的解释: http : //msdn.microsoft.com/en-us/library/s6938f28.aspx

文章摘要:

引用types的variables不直接包含其数据; 它包含对其数据的引用。 当按值传递引用types参数时,可以更改引用指向的数据,例如类成员的值。 但是,您不能更改引用本身的值; 也就是说,不能使用相同的引用为新类分配内存,并将其保留在块之外。 为此,请使用ref或out关键字传递参数。

使用ref关键字传递引用types时,通过引用传递引用,并且调用的方法可以为参数分配一个新值。 该更改将传播到调用范围。 没有引用,引用是通过价值传递,这不会发生。

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

它允许你修改传入的引用

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

除了现有的答案:

当你问两种方法的区别:使用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 } 

在一个方法中的参数似乎总是通过一个副本,问题是什么副本。 复制是由一个对象的复制构造函数完成的,因为所有variables都是C#中的Object,我相信这是所有这些情况。 variables(对象)就像生活在某个地址的人。 我们要么改变居住在这些地址的人们,要么为生活在电话簿地址上的人们创build更多的参考(制作浅表副本)。 因此,多个标识符可以指向相同的地址。 引用types需要更多的空间,因此与堆栈中的标识符直接通过箭头直接连接的值types不同,它们具有堆中另一个地址的值(留有更大的空间)。 这个空间需要从堆中取出。

值types:标识符(包含值=堆栈值的地址)—->值types的值

引用types:标识符(包含值=堆栈值的地址)—->(包含值=堆值的地址)—->堆值(通常包含其他值的地址),想象更多箭头粘在不同的值Array [0],Array [1],array [2]

改变一个值的唯一方法是跟随箭头。 如果一个箭头丢失/改变的方式是无法访问的值。