C#中ref与out的使用
2010-04-07 22:29 Eric.Hu 阅读(477) 评论(1) 编辑 收藏 举报—— 以下信息均来自网上,后边会稍加自己的总结 ——
c#的类型分为两种:值类型和引用类型:
值类型: 简单类型(包括int, long, double等)和结构(structs)都是值类型
引用类型:除了值类型以外的都是引用类型。
- REF
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。例如:
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 参数,则无法重载这两个方法。例如,从编译的角度来看,以下代码中的两个方法是完全相同的,因此将不会编译以下代码:
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 参数,而另一个方法不采用这两个参数,则可以进行重载,如下例所示:
2 {
3 public void SampleMethod(int i) { }
4 public void SampleMethod(ref int i) { }
5 }
属性不是变量,因此不能作为 ref 参数传递。
示例:
按引用传递值类型(如本主题前面所示)是有用的,但是 ref 对于传递引用类型也是很有用的。这允许被调用的方法修改该引用所引用的对象,因为引用本身是按引用来传递的。下面的示例显示出当引用类型作为 ref 参数传递时,可以更改对象本身。
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
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 参数,则无法重载这两个方法。例如,从编译的角度来看,以下代码中的两个方法是完全相同的,因此将不会编译以下代码:
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。这样便允许方法有选择地返回值。
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 参数前必须先为其赋值,即必须由被调用方为其赋值。例如:
2 {
3 arr = new int[10]; // definite assignment of arr
4 }
与所有的 ref 参数一样,数组类型的 ref 参数必须由调用方明确赋值。因此不需要由接受方明确赋值。可以将数组类型的 ref 参数更改为调用的结果。例如,可以为数组赋以 null 值,或将其初始化为另一个数组。例如:
2 {
3 arr = new int[10]; // arr initialized to a different array
4 }
5
下面的两个示例说明 out 与 ref 在将数组传递给方法时的用法差异。
示例1
在此例中,在调用方(Main 方法)中声明数组 theArray,并在 FillArray 方法中初始化此数组。然后将数组元素返回调用方并显示。
1 class TestOut
3 static void FillArray(out int[] arr)
4 {
5 // Initialize the array:
6 arr = new int[5] { 1, 2, 3, 4, 5 };
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 方法中更新某些数组元素。然后将数组元素返回调用方并显示。
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 = { 1, 2, 3, 4, 5 };
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
总结: