Why ref and out in C#?
当使用关键字
- 为什么我们不到处使用
out ? - 两者的确切区别是什么?
- 请举例说明我们需要使用
ref 而不能使用out 的情况。
答案在这个msdn文章中给出。从那个帖子:
The two parameter passing modes
addressed byout andref are subtly
different, however they are both very
common. The subtle difference between
these modes leads to some very common
programming errors. These include:not assigning a value to an out
parameter in all control flow pathsnot assigning a value to variable
which is used as aref parameterBecause the C# language assigns
different definite assignment rules to
these different parameter passing
modes, these common coding errors are
caught by the compiler as being
incorrect C# code.The crux of the decision to include
bothref andout parameter passing
modes was that allowing the compiler
to detect these common coding errors
was worth the additional complexity of
having bothref andout parameter
passing modes in the language.
在这种情况下,C编译器强制在方法返回之前分配
1 2 3 4 5 6 7 8 | void NoOp(out int value) // value must be assigned before method returns { } void Increment(out int value) // value cannot be used before it has been assigned { value = value + 1; } |
这些答案都不能让我满意,所以我来看看我对
我的答案是以下两页的摘要:
比较
对比度
实例
不会编译,因为方法签名的唯一区别是
1 2 | public void Add(out int i) { } public void Add(ref int i) { } |
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public void PrintNames(List<string> names) { int index = 0; // initialize first (#1) foreach(string name in names) { IncrementIndex(ref index); Console.WriteLine(index.ToString() +"." + name); } } public void IncrementIndex(ref int index) { index++; // initial value was passed in (#2) } |
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public void PrintNames(List<string> names) { foreach(string name in names) { int index; // not initialized (#1) GetIndex(out index); Console.WriteLine(index.ToString() +"." + name); } } public void GetIndex(out int index) { index = IndexHelper.GetLatestIndex(); // needs to be assigned a value (#2 & #3) } |
作者的随意评论
例子:
1 2 3 4 5 | public void ReassignArray(ref int[] array) { array = new int[10]; // now the array in the calling code // will point to this new object } |
有关引用类型与值类型的详细信息,请参阅传递引用类型参数(C编程指南)
ref关键字允许您更改参数的值。正在调用的方法可以是调用链中的中间链接。使用out关键字的方法只能在调用链的开头使用。
另一个优点是现有的值可以在方法的逻辑中使用,并且仍然保留返回值。
在Oracle中,函数有显式的in/out和out参数(默认值以及如果不设置方向会得到什么)。等效值为正常值(仅为参数)、ref[参数]和out[参数]。
当您需要使用ref而不是out时,一个人为的示例如下:
1 2 3 4 5 6 7 | public void SquareThisNumber(ref int number) { number = number * number; } int number = 4; SquareThisNumber(ref number); |
这里我们希望
当我们在调用以
所以
当需要从特定方法返回多个值时,使用
而对于
编译器知道out变量不应该在调用之前设置。这允许在使用前声明它们。然而,它知道必须在返回中使用的函数之前设置它。