在C#中使用’ref’关键字

可能重复:
为什么在传递Object时使用ref关键字?
何时传递ref关键字

C#中’ref’关键字的正确用法是什么? 我相信这方面有很多讨论主题,但我不清楚的是:

  1. 如果要传入引用对象,是否需要ref关键字? 我的意思是当你在堆中创建一个对象时,它并不总是通过引用传递。 这是否必须明确标记为ref?

使用ref意味着将引用传递给函数。

默认行为是函数接收对同一对象的新引用。 这意味着如果更改引用的值(例如,将其设置为新对象),则不再指向原始源对象。 当您使用ref传递时,更改引用的值会更改源引用 – 因为它们是相同的。

考虑一下:

 public class Thing { public string Property {get;set;} } public static void Go(Thing thing) { thing = new Thing(); thing.Property = "Changed"; } public static void Go(ref Thing thing) { thing = new Thing(); thing.Property = "Changed"; } 

如果你跑了

 var g = new Thing(); // this will not alter g Go(g); // this *will* alter g Go(ref g); 

这里的答案中有很多令人困惑的错误信息。 理解这一点的最简单方法是放弃“ref”的意思是“通过引用”。 考虑它的一个更好的方法是“ref”意味着“我希望被叫方的这个forms参数成为调用方的特定变量的别名”。

当你说

 void M(ref int y) { y = 123; } ... int x = 456; M(ref x); 

也就是说“在调用M时,被调用方的forms参数y是调用者侧变量x的另一个名称”。 将123分配给y与将123分配给x完全相同,因为它们是相同的变量 ,具有两个名称的变量。

就这样。 不要考虑引用类型或值类型或其他,不考虑通过引用传递或通过值传递。 所有“ref”意味着“暂时为此变量创建第二个名称”。

我相信ref关键字表示您通过引用而不是值传递对象。 例如:

 void myfunction(ref object a) { a = new Something(); } 

会改变调用函数中a的值但是,

 void myfunction(object a) { a = new Something(); } 

会改变本地的值,但不会改变调用函数的值。 您仍然可以更改项目的属性,但不能设置项目本身的值。 例如; a.someproperty = value;

会在两种情况下都有效。

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace InOutRef { static class InOutRef { public static void In(int i) { Console.WriteLine(i); i=100; Console.WriteLine(i); } public static void Ref(ref int i) { Console.WriteLine(i); i=200; Console.WriteLine(i); } public static void Out(out int i) { //Console.WriteLine(i); //Error Unsigned Ref i=300; Console.WriteLine(i); } } class Program { static void Main(string[] args) { int i = 1; InOutRef.In(i); //passed by value (in only) Debug.Assert(i==1); InOutRef.Ref(ref i); //passed by ref (in or out) Debug.Assert(i == 200); InOutRef.Out(out i); //passed by as out ref (out only) Debug.Assert(i == 300); } } } 

在我的回答中我不能再是字面意义了。 代码将不会记住引用通道,例如使用时的经典Java交换问题 。 但是,当使用ref时 ,它将类似于VB.NET,因为它会记住进出的变化。 如果使用out参数,则意味着必须在返回之前声明它(这由编译器强制执行)。

输出:
 1 // 1来自main 
 100 // 100来自in
 1 // 1不会从In中记住
来自参考的200 // 200
 //这里应该是200但是强制执行param(因为已注释掉而没有打印)
 300 // 300仅限
按任意键继续 。  。  。