C#中应用参数ref 和 输出参数out


从CLR的角度看,关键字out和关键字ref是等效的,这就是说,无论使用哪个关键字,都会生成相同的元数据和IL代码。但是,C#编译器将两个关键字区别对待,在C#中,这两个关键字的区别在于哪个方法负责初始化引用对象。如果方法的参数标记为out,那么调用者不希望在调用方法之前初始化对象,被调用的方法不能读取对象的值,而且被调用的方法必须在返回之前为对象赋值。如果方法的参数标记为ref,那么调用者必须在调用方法之前首先初始化参数的值,被调用的方法可以读取参数或为参数赋值。

  1. namespace 方法参数  
  2. {  
  3.     /// <summary>  
  4.     /// 参数测试  
  5.     /// </summary>  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         {  
  10.             //输出参数  
  11.             Point p = new Point(10, 12);  
  12.             int x, y;//输出参数不需要赋初值//与引用类型相似,输出参数也不开辟新的内存区域,   
  13. 但在调用方法前无需对变量进行初始化。  
  14.             p.GetPoint(out x, out y);  
  15.             Console.WriteLine("p({0},{1})", x, y);  
  16.             //引用参数  
  17.             Point2 p1 = new Point2(12, 23);  
  18.             int x1 = 0, y1 = 0;//引用参数一定要赋初值  
  19.             p1.GetPoint(ref x1, ref y1);  
  20.             Console.WriteLine("p1({0},{1})", x1, y1);  
  21.             // 参数数组  
  22.             int[] a = { 1, 2, 3, 4, 5 };  
  23.             Array.F(a);  
  24.             Array.F(10, 20, 30, 60, 50);//F(new int[] {10, 20, 30, 60, 50})  
  25.             Array.F();  
  26.             Console.ReadLine();  
  27.         }  
  28.     }  
  29.     /// <summary>  
  30.     /// 输出参数可返回多个值  
  31.     /// </summary>  
  32.     class Point  
  33.     {  
  34.         int X, Y;  
  35.         public Point(int x, int y)  
  36.         {  
  37.             this.X = x;  
  38.             this.Y = y;  
  39.         }  
  40.         public void GetPoint(out int x, out int y)//输出参数用于传递方法返回的数据。out修饰符后应跟与形参类型相同的类型申明。在方法返回后,传递的变量被认为经过了初始化。  
  41.         {  
  42.             y = this.Y;  
  43.             x = this.X;  
  44.         }  
  45.     }  
  46.     /// <summary>  
  47.     /// 引用参数  
  48.     /// </summary>  
  49.     class Point2  
  50.     {  
  51.         int X, Y;  
  52.         public Point2(int x, int y)  
  53.         {  
  54.             this.X = x;  
  55.             this.Y = y;  
  56.         }  
  57.         public void GetPoint(ref int x, ref int y)  
  58.         {  
  59.             y = this.Y;  
  60.             x = this.X;  
  61.         }  
  62.     }  
  63.     /// <summary>  
  64.     /// 参数数组  
  65.     /// </summary>  
  66.     class Array  
  67.     {  
  68.         public static void F(params int[] args)  
  69.         {  
  70.             Console.WriteLine("数组长度为:{0}", args.Length);  
  71.             foreach (int i in args)  
  72.             {  
  73.                 Console.WriteLine("{0}", i);  
  74.             }  
  75.             Console.WriteLine();  
  76.         }  
  77.     }  

out parameter modifier (C# Reference)

The out keyword causes arguments to be passed by reference. This is like the ref keyword, except that ref requires that the variable be initialized before it is passed. To use an out parameter, both the method definition and the calling method must explicitly use the out keyword. For example:

C#
class OutExample { static void Method(out int i) { i = 44; } static void Main() { int value; Method(out value); // value is now 44 } } 

Although variables passed as out arguments do not have to be initialized before being passed, the called method is required to assign a value before the method returns.

Although the ref and out keywords cause different run-time behavior, they are not considered part of the method signature at compile time. Therefore, methods cannot be overloaded if the only difference is that one method takes a ref argument and the other takes an out argument. The following code, for example, will not compile:

C#
class CS0663_Example { // Compiler error CS0663: "Cannot define overloaded  // methods that differ only on ref and out". public void SampleMethod(out int i) { } public void SampleMethod(ref int i) { } } 

Overloading can be done, however, if one method takes a ref or out argument and the other uses neither, like this:

C#
class OutOverloadExample { public void SampleMethod(int i) { } public void SampleMethod(out int i) { i = 5; } } 

Properties are not variables and therefore cannot be passed as out parameters.

For information about passing arrays, see Passing Arrays Using ref and out (C# Programming Guide).

Example

Declaring an out method is useful when you want a method to return multiple values. The following example uses out to return three variables with a single method call. Note that the third argument is assigned to null. This enables methods to return values optionally.

C#
 class OutReturnExample { static void Method(out int i, out string s1, out string s2) { i = 44; s1 = "I've been returned"; s2 = null; } static void Main() { int value; string str1, str2; Method(out value, out str1, out str2); // value is now 44 // str1 is now "I've been returned" // str2 is (still) null; } }

ref(C# 参考)

ref 关键字使参数按引用传递。 其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。

注意注意

不要将“通过引用传递”概念与“引用类型”概念相混淆。 这两个概念不同。 方法参数无论是值类型还是引用类型,都可通过 ref 进行修饰。 通过引用传递值类型时没有值类型装箱。

若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。 例如:

C#
 class RefExample { static void Method(ref int i) { // Rest the mouse pointer over i to verify that it is an int. // The following statement would cause a compiler error if i // were boxed as an object. i = i + 44; } static void Main() { int val = 1; Method(ref val); Console.WriteLine(val); // Output: 45 } }

传递到 ref 参数的参数必须最先初始化。 这与 out 不同,后者的参数在传递之前不需要显式初始化。 有关更多信息,请参见 out。

尽管 ref 和 out 关键字会导致不同的运行时行为,但在编译时并不会将它们视为方法签名的一部分。 因此,如果两个方法唯一的区别是:一个接受 ref 参数,另一个接受 out 参数,则无法重载这两个方法。 例如,不会编译下面的代码:

C#
class CS0663_Example { // Compiler error CS0663: "Cannot define overloaded  // methods that differ only on ref and out". public void SampleMethod(out int i) { } public void SampleMethod(ref int i) { } }

但是,如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两个参数,则可以进行重载,如下例所示:

C#
 class RefOverloadExample { public void SampleMethod(int i) { } public void SampleMethod(ref int i) { } }

属性不是变量。 它们实际上是方法,因此不能作为 ref 参数进行传递。

有关如何传递数组的信息,请参见使用 ref 和 out 传递数组(C# 编程指南)

示例

按引用传递值类型(如本主题前面所示)是有用的,但是 ref 对于传递引用类型也是很有用的。 这允许被调用的方法修改该引用所引用的对象,因为引用本身是按引用来传递的。 下面的示例显示出当引用类型作为 ref 参数传递时,可以更改对象本身。 有关更多信息,请参见 传递引用类型参数(C# 编程指南)

C#
class RefExample2 { static void Method(ref string s) { s = "changed"; } static void Main() { string str = "original"; Method(ref str); Console.WriteLine(str); } } // Output: changed

相关内容