您的位置:首页 > 编程语言 > C#

(C#)方法参数关键字:ref、out、params详解

2010-12-22 10:26 609 查看

(C#)方法参数关键字:ref、out、params详解

备注:以下来自MSDN和网络参考,经过整理后的文档

ref(C# 参考)

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

{

static void Method(ref int i)

{

i = 44;

}

static void Main()

{

int val = 0; //使用ref val必须先初始化

Method(ref val);

// val is now 44

}

}

Ø 传递到 ref 参数的参数必须最先初始化。这与 out 不同,后者的参数在传递之前不需要显式初始化。
尽管 refout 在运行时的处理方式不同,但在编译时的处理方式相同。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。例如,从编译的角度来看,以下代码中的两个方法是完全相同的,因此将不会编译以下代码:

class CS0663_Example

{

// Compiler error CS0663: "cannot define overloaded

// methods that differ only on ref and out".

public void SampleMethod(ref int i) { }

public void SampleMethod(out int i) { }

}

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

class RefOutOverloadExample

{

public void SampleMethod(int i) { }

public void SampleMethod(ref int i) { }

}

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

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

class RefRefExample

{

static void Method(ref string s)

{

s = "changed";

}

static void Main()

{

string str = "original";

Method(ref str);

// str is now "changed"

}

}

out(C# 参考)

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

class OutExample

{

static void Method(out int i)

{

i = 44;

}

static void Main()

{

int value; //使用out ,value不必初始化

Method(out value);

// value is now 44

}

}

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

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

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;

}

}

params(C# 参考)

params 关键字可以指定在参数数目可变处采用参数的方法参数。

Ø 在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。

// cs_params.cs

using System;

public class MyClass

{

public static void UseParams(params int[] list)

{

for (int i = 0 ; i < list.Length; i++)

{

Console.WriteLine(list[i]);

}

Console.WriteLine();

}

public static void UseParams2(params object[] list)

{

for (int i = 0 ; i < list.Length; i++)

{

Console.WriteLine(list[i]);

}

Console.WriteLine();

}

static void Main()

{

UseParams(1, 2, 3);

UseParams2(1, 'a', "test");

// An array of objects can also be passed, as long as

// the array type matches the method being called.

int[] myarray = new int[3] {10,11,12};

UseParams(myarray);

}

}

输出:

1

2

3

1

a

test

10

11

12

使用 ref 和 out 传递数组(C# 编程指南)

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

static void TestMethod1(out int[] arr)

{

arr = new int[10]; // definite assignment of arr

}

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

static void TestMethod2(ref int[] arr)

{

arr = new int[10]; // arr initialized to a different array

}

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

示例 1:

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

{

static void FillArray(out int[] arr)

{

// Initialize the array:

arr = new int[5] { 1, 2, 3, 4, 5 };

}

static void Main()

{

int[] theArray; // Initialization is not required

// Pass the array to the callee using out:

FillArray(out theArray);

// Display the array elements:

System.Console.WriteLine("Array elements are:");

for (int i = 0; i < theArray.Length; i++)

{

System.Console.Write(theArray[i] + " ");

}

}

}

输出 1

Array elements are:

1 2 3 4 5

示例 2

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

class TestRef

{

static void FillArray(ref int[] arr)

{

// Create the array on demand:

if (arr == null)

{

arr = new int[10];

}

// Fill the array:

arr[0] = 1111;

arr[4] = 5555;

}

static void Main()

{

// Initialize the array:

int[] theArray = { 1, 2, 3, 4, 5 };

// Pass the array using ref:

FillArray(ref theArray);

// Display the updated array:

System.Console.WriteLine("Array elements are:");

for (int i = 0; i < theArray.Length; i++)

{

System.Console.Write(theArray[i] + " ");

}

}

}

输出 2

Array elements are:

1111 2 3 4 5555

ref和out的区别:

通常我们向方法中传递的是值.方法获得的是这些值的一个拷贝,然后使用这些拷贝,当方法运行完毕后,这些拷贝将被丢弃,而原来的值不将受到影响.此外我们还有其他向方法传递参数的形式,引用(ref)和输出(out).

有时,我们需要改变原来变量中的值,这时,我们可以向方法传递变量的引用,而不是变量的值.引用是一个变量,他可以访问原来变量的值,修改引用将修改原来变量的值.变量的值存储内存中,可以创建一个引用,他指向变量在内存中的位置.当引用被修改时,修改的是内存中的值,因此变量的值可以将被修改.当我们调用一个含有引用参数的方法时,方法中的参数将指向被传递给方法的相应变量,因此,我们会明白,为什么当修改参数变量的修改也将导致原来变量的值.
我们发现,ref和out似乎可以实现相同的功能.因为都可以改变传递到方法中的变量的值.但是,二者本质本质的区别就是,ref是有进有出,out是只出不进.在含有out关键字的方法中,变量必须由方法参数中不含out(可以是ref)的变量赋值或者由全局(即方法可以使用的该方法外部变量)变量赋值,out的宗旨是保证每一个传出变量都必须被赋值.
ref和out的比较:
1、使用ref型参数时,传入的参数必须先被初始化。对out而言,必须在方法中对其完成初始化,因为out的函数会清空变量,即使变量已经赋值也不行,退出函数时所有out引用的变量都要赋值,ref引用的可以修改,也可以不修改。
2、使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字。以满足匹配。
3、out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。  
  区别可以参看下面的代码:
using System;
class TestApp
{
 static void outTest(out int x, out int y)
 {//离开这个函数前,必须对x和y赋值,否则会报错。
  //y = x;
  //上面这行会报错,因为使用了out后,x和y都清空了,需要重新赋值,即使调用函数前赋过值也不行
  x = 1;
  y = 2;
 }
 static void refTest(ref int x, ref int y)
 {
  x = 1;
  y = x;
 }
 public static void Main()
 {
  //out test
  int a,b;
  //out使用前,变量可以不赋值
  outTest(out a, out b);
  Console.WriteLine("a={0};b={1}",a,b);
  int c=11,d=22;
  outTest(out c, out d);
  Console.WriteLine("c={0};d={1}",c,d);
  //ref test
  int m,n;
  //refTest(ref m, ref n);
  //上面这行会出错,ref使用前,变量必须赋值
  int o=11,p=22;
  refTest(ref o, ref p);
  Console.WriteLine("o={0};p={1}",o,p);
 }
}
注:在C#中,方法的参数传递有四种类型:
1、 传值(by value)
2、 传址(by reference)
3、 输出参数(by output)
4、 数组参数(by array)。
传值参数无需额外的修饰符,传址参数需要修饰符ref,输出参数需要修饰符out,数组参数需要修饰符params。
传值参数在方法调用过程中如果改变了参数的值,那么传入方法的参数在方法调用完成以后并不因此而改变,而是保留原来传入时的值。
传址参数恰恰相反,如果方法调用过程改变了参数的值,那么传入方法的参数在调用完成以后也随之改变。实际上从名称上我们可以清楚地看出两者的含义--传值参数传递的是调用参数的一份拷贝,而传址参数传递的是调用参数的内存地址,该参数在方法内外指向的是同一个存储位置。
方法参数上的 ref 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
若要使用 ref 参数,必须将参数作为 ref 参数显式传递到方法。ref 参数的值被传递到 ref 参数。

查看原文:/article/6396163.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: