ref 关键字通过引用(而非值)传递参数。 通过引用传递的效果是,对所调用方法中的参数进行的任何更改都反映在调用方法中。
说明: 不要混淆通过引用传递的概念与引用类型的概念。 这两种概念是不同的。 无论方法参数是值类型还是引用类型,均可由 ref 修改。 当通过引用传递时,不会对值类型装箱。
若要使用 ref 参数,方法定义和调用方法均必须显式使用 ref 关键字,如下面的示例所示。
1 class RefExample 2 { 3 static void Method(ref int i) 4 { 5 // Rest the mouse pointer over i to verify that it is an int. 6 // The following statement would cause a compiler error if i 7 // were boxed as an object. 8 i = i + 44; 9 } 10 11 static void Main() 12 { 13 int val = 1; 14 Method(ref val); 15 Console.WriteLine(val); 16 17 // Output: 45 18 } 19 }
传递到 ref 形参的实参必须先经过初始化,然后才能传递。 这与 out 形参不同,在传递之前,不需要显式初始化该形参的实参。
类的成员不能具有仅在 ref 和 out 方面不同的签名。 如果类型的两个成员之间的唯一区别在于其中一个具有 ref 参数,而另一个具有 out 参数,则会发生编译错误。 例如,以下代码将不会编译。
1 class CS0663_Example 2 { 3 // Compiler error CS0663: "Cannot define overloaded 4 // methods that differ only on ref and out". 5 public void SampleMethod(out int i) { } 6 public void SampleMethod(ref int i) { } 7 }
但是,当一个方法具有 ref 或 out 参数,另一个方法具有值参数时,则可以完成重载,如下面的示例所示。
class RefOverloadExample { public void SampleMethod(int i) { } public void SampleMethod(ref int i) { } }
你不能将 ref 和 out 关键字用于以下几种方法:
-
异步方法,通过使用 async 修饰符定义。
-
迭代器方法,包括 yield return 或 yield break 语句。
还可以使用 ref 关键字传递引用类型:

1 class RefExample2 2 { 3 static void ChangeByReference(ref Product itemRef) 4 { 5 // The following line changes the address that is stored in 6 // parameter itemRef. Because itemRef is a ref parameter, the 7 // address that is stored in variable item in Main also is changed. 8 itemRef = new Product("Stapler", 99999); 9 10 // You can change the value of one of the properties of 11 // itemRef. The change happens to item in Main as well. 12 itemRef.ItemID = 12345; 13 } 14 15 static void Main() 16 { 17 // Declare an instance of Product and display its initial values. 18 Product item = new Product("Fasteners", 54321); 19 System.Console.WriteLine("Original values in Main. Name: {0}, ID: {1} ", 20 item.ItemName, item.ItemID); 21 22 // Send item to ChangeByReference as a ref argument. 23 ChangeByReference(ref item); 24 System.Console.WriteLine("Back in Main. Name: {0}, ID: {1} ", 25 item.ItemName, item.ItemID); 26 } 27 } 28 29 class Product 30 { 31 public Product(string name, int newID) 32 { 33 ItemName = name; 34 ItemID = newID; 35 } 36 37 public string ItemName { get; set; } 38 public int ItemID { get; set; } 39 } 40 41 // Output: 42 //Original values in Main. Name: Fasteners, ID: 54321 43 44 //Back in Main. Name: Stapler, ID: 12345
out 关键字会导致参数通过引用来传递。 这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。 若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。尽管作为 out 参数传递的变量不必在传递之前进行初始化,但被调用的方法必须在返回之前赋一个值。