代码改变世界

C#中ref与out的使用

2010-04-07 22:29  Eric.Hu  阅读(477)  评论(1编辑  收藏  举报

—— 以下信息均来自网上,后边会稍加自己的总结 ——

c#的类型分为两种:值类型和引用类型:

值类型: 简单类型(包括int, long, double等)和结构(structs)都是值类型

引用类型:除了值类型以外的都是引用类型。

  • REF 

 ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。例如:

 1 class RefExample
 2 {
 3     static void Method(ref int i)
 4     {
 5         i = 44;
 6     }
 7     static void Main()
 8     {
 9         int val = 0;
10         Method(ref val);
11         // val is now 44
12     }
13 }

 

 传递到 ref 参数的参数必须最先初始化。这与 out 不同,后者的参数在传递之前不需要显式初始化。有关更多信息,请参见 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 参数,而另一个方法不采用这两个参数,则可以进行重载,如下例所示:

1 class RefOverloadExample
2 {
3     public void SampleMethod(int i) { }
4     public void SampleMethod(ref int i) { }
5 }

 

 属性不是变量,因此不能作为 ref 参数传递。

 

示例:

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

 1 class RefExample2
 2 {
 3     static void Method(ref string s)
 4     {
 5         s = "changed";
 6     }
 7     static void Main()
 8     {
 9         string str = "original";
10         Method(ref str);
11         Console.WriteLine(str);
12     }
13 }
14 // Output: changed
15 

 

 

  • OUT 

 out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。例如:

  1 class OutExample

 2 {
 3     static void Method(out int i)
 4     {
 5         i = 44;
 6     }
 7     static void Main()
 8     {
 9         int value;
10         Method(out value);
11         // value is now 44
12     }
13 }

 

 

 尽管作为 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 }

 

 

 示例:

当希望方法返回多个值时,声明 out 方法很有用。使用 out 参数的方法仍然可以将变量用作返回类型,但它还可以将一个或多个对象作为 out 参数返回给调用方法。此示例使用 out 在一个方法调用中返回三个变量。请注意,第三个参数所赋的值为 Null。这样便允许方法有选择地返回值。

 1 class OutReturnExample
 2 {
 3     static void Method(out int i, out string s1, out string s2)
 4     {
 5         i = 44;
 6         s1 = "I've been returned";
 7         s2 = null;
 8     }
 9     static void Main()
10     {
11         int value;
12         string str1, str2;
13         Method(out value, out str1, out str2);
14         // value is now 44
15         // str1 is now "I've been returned"
16         // str2 is (still) null;
17     }
18 }

 

 

 

使用 ref 和 out 传递数组

与所有的 out 参数一样,在使用数组类型的 out 参数前必须先为其赋值,即必须由被调用方为其赋值。例如:

1 static void TestMethod1(out int[] arr)
2 {
3     arr = new int[10];   // definite assignment of arr
4 }

 

 

与所有的 ref 参数一样,数组类型的 ref 参数必须由调用方明确赋值。因此不需要由接受方明确赋值。可以将数组类型的 ref 参数更改为调用的结果。例如,可以为数组赋以 null 值,或将其初始化为另一个数组。例如: 

1 static void TestMethod2(ref int[] arr)
2 {
3     arr = new int[10];   // arr initialized to a different array
4 }
5 

 

 

下面的两个示例说明 out 与 ref 在将数组传递给方法时的用法差异。

 示例1

 在此例中,在调用方(Main 方法)中声明数组 theArray,并在 FillArray 方法中初始化此数组。然后将数组元素返回调用方并显示。

  1 class TestOut

 2 {
 3     static void FillArray(out int[] arr)
 4     {
 5         // Initialize the array:
 6         arr = new int[5] { 12345 };
 7     }
 8 
 9     static void Main()
10     {
11         int[] theArray; // Initialization is not required
12 
13         // Pass the array to the callee using out:
14         FillArray(out theArray);
15 
16         // Display the array elements:
17         System.Console.WriteLine("Array elements are:");
18         for (int i = 0; i < theArray.Length; i++)
19         {
20             System.Console.Write(theArray[i] + " ");
21         }
22     }
23 }

 

结果:

Array elements are:

1 2 3 4 5

 

 示例2:

 在此例中,在调用方(Main 方法)中初始化数组 theArray,并通过使用 ref 参数将其传递给 FillArray 方法。在 FillArray 方法中更新某些数组元素。然后将数组元素返回调用方并显示。

 1 class TestRef
 2 {
 3     static void FillArray(ref int[] arr)
 4     {
 5         // Create the array on demand:
 6         if (arr == null)
 7         {
 8             arr = new int[10];
 9         }
10         // Fill the array:
11         arr[0= 1111;
12         arr[4= 5555;
13     }
14 
15     static void Main()
16     {
17         // Initialize the array:
18         int[] theArray = { 12345 };
19 
20         // Pass the array using ref:
21         FillArray(ref theArray);
22 
23         // Display the updated array:
24         System.Console.WriteLine("Array elements are:");
25         for (int i = 0; i < theArray.Length; i++)
26         {
27             System.Console.Write(theArray[i] + " ");
28         }
29     }
30 }

 

结果:

Array elements are:

1111 2 3 4 5555 

 

总结: