Can anyone tell me the exact usage of the "out" keyword as a paramter, and how its connected to returning multiple values from a function, as in the Return multiple values to a method caller post.
I am confused with the "out" variable vs a normal variable.
This is frequently confusing, and I think the MSDN documentation actually is a bit "clear only if already known". That is, it is correct, but it really only makes sense if you already understand the concept.
Here's how I think of it.
A regular parameter makes a copy of the value of the argument. When you say:
static int M(int z) { z = z + 1; return z; }
...
int x = 123;
int y = M(x);
That is just like you said:
int x = 123;
int z = x; // make a copy of x
z = z + 1;
int y = z;
A ref or out parameter make an alias for an existing variable. When you say
static void N(ref int q) { q = q + 1; }
...
int x = 123;
N(x);
That is the same as saying:
int x = 123;
// MAGIC: q is now an another name for variable x
q = q + 1;
q and x are two different names that refer to the same variable. Incrementing q also increments x because they are the same. z and x in the previous example are two different names that refer to two different variables. Incrementing z does not change x.
Summing up: "out" and "ref" just mean "do not make a new variable; rather, temporarily make a second name for an existing variable".
Is that now clear?
UPDATE: I did not say what the difference between "out" and "ref" is. The difference is simple. On the "caller" side, a "ref" must be a definitely assigned variable before the method is called. An "out" need not be. On the "callee" side, a "ref" may be read before it is written to, but an "out" must be written to before it is read. Also, an "out" must be written to before control leaves the method normally.
The out keyword causes arguments to be passed by reference. This is
similar to the ref keyword, except that ref requires that the variable
be initialized before being passed. To use an out parameter, both the
method definition and the calling method must explicitly use the out
keyword. For example:
class OutExample
{
static void Method(out int i)
{
i = 44;
}
static void Main()
{
int value;
Method(out value);
// value is now 44
}
}
In most languages, C# included, you can pass values in 2 ways:
by value or by reference.
By value gives the method a copy of your data, so changing the data wont have any effect on the original data.
By reference essentially gives the method the memory address of your data, so if the method modifies the data, it changes the original data.
The "out" keyword is a special type of by reference, in that you do not need to initialise the variable before you call the method. It can be called with null being passed in and it MUST be set by the method.
Another way you can think of it (from the outside code's point of view) is:
当您想要执行以下操作时,应使用 out 关键字:
a) 允许您的函数修改调用代码堆栈中的特定变量并且
b) 强制在函数内设置此变量值
out keyword should be used when you want to:
a) Allow your function to modify specific variable from calling code stack AND
b) enforce setting this variable value inside your function
out keyword is good if you want to return multiple values of pre-defined types (for example an int, a List<string> and a DateTime), and you don't want to create a new class just for this purpose.
let look at the usual pattern for this kind of function - the TrySomething.
Suppose you have a function that might succeed giving you an value or not but you don't won't to use an exception for this because you don't want the overhead or it's a common trait.
Then you normaly return true if the method suceeded and false if not. But where would you put your outputvalue to?
One possible answer is using an out parameter like this:
bool TrySomething(MyInputType input, out MyOutputType output)
{
output = default(MyOutputType);
/* ... Try getting the answer ... */
if (!successful)
return false;
output = successfulOutput;
return true;
}
Remark:
Or you might consider using a Tuple<bool,MyOutputType> and indeed F# interpretes the pattern above as resulting in such a tuple by itself.
发布评论
评论(8)
这经常令人困惑,我认为 MSDN 文档实际上有点“只有在已知的情况下才清晰”。也就是说,它是正确的,但只有当你已经理解这个概念时它才有意义。
我是这样想的。
常规参数会复制参数的值。当你说:
这就像你说的那样:
引用或输出参数为现有变量创建别名。当您说
这与说:
q
和x
是引用同一个变量的两个不同名称时 相同>。递增q
也会递增x
,因为它们是相同的。上一个示例中的z
和x
是两个不同的名称,它们引用两个不同的变量。增加z
不会改变x
。总结:“out”和“ref”只是意味着“不要创建新变量;而是暂时为现有变量创建第二个名称”。
现在清楚了吗?
更新:我没有说“out”和“ref”之间的区别是什么。区别很简单。在“调用者”方面,“ref”必须是调用方法之前明确分配的变量。不一定要“出局”。在“被调用者”一侧,可以在写入“ref”之前读取“ref”,但必须在读取“out”之前写入“out”。此外,在控制正常离开方法之前必须写入“out”。
This is frequently confusing, and I think the MSDN documentation actually is a bit "clear only if already known". That is, it is correct, but it really only makes sense if you already understand the concept.
Here's how I think of it.
A regular parameter makes a copy of the value of the argument. When you say:
That is just like you said:
A ref or out parameter make an alias for an existing variable. When you say
That is the same as saying:
q
andx
are two different names that refer to the same variable. Incrementingq
also incrementsx
because they are the same.z
andx
in the previous example are two different names that refer to two different variables. Incrementingz
does not changex
.Summing up: "out" and "ref" just mean "do not make a new variable; rather, temporarily make a second name for an existing variable".
Is that now clear?
UPDATE: I did not say what the difference between "out" and "ref" is. The difference is simple. On the "caller" side, a "ref" must be a definitely assigned variable before the method is called. An "out" need not be. On the "callee" side, a "ref" may be read before it is written to, but an "out" must be written to before it is read. Also, an "out" must be written to before control leaves the method normally.
MSDN 文档 已经做得很好了解释一下:
MSDN documentation already does a great job explaining this:
它经常用于“尝试”获取值的模式,例如:
It's very frequently used in a pattern that "tries" to get a value, something like:
在大多数语言(包括 C#)中,您可以通过两种方式传递值:
按值或按引用。
按值为该方法提供数据的副本,因此更改数据不会对原始数据产生任何影响。
通过引用实质上为该方法提供了数据的内存地址,因此如果该方法修改了数据,它就会更改原始数据。
“out”关键字是一种特殊的引用类型,因为您不需要在调用方法之前初始化变量。可以通过传入 null 来调用它,并且它必须由该方法设置。
您可以想到的另一种方式(从外部代码的角度)是:
val = read only
ref = 读/写
输出 = 只写
In most languages, C# included, you can pass values in 2 ways:
by value or by reference.
By value gives the method a copy of your data, so changing the data wont have any effect on the original data.
By reference essentially gives the method the memory address of your data, so if the method modifies the data, it changes the original data.
The "out" keyword is a special type of by reference, in that you do not need to initialise the variable before you call the method. It can be called with null being passed in and it MUST be set by the method.
Another way you can think of it (from the outside code's point of view) is:
val = read only
ref = read/write
out = write only
当您想要执行以下操作时,应使用
out
关键字:a) 允许您的函数修改调用代码堆栈中的特定变量并且
b) 强制在函数内设置此变量值
out
keyword should be used when you want to:a) Allow your function to modify specific variable from calling code stack AND
b) enforce setting this variable value inside your function
MSDN 始终是一个不错的起点
MSDN is always a good place to start
http://msdn.microsoft.com/en-如果
您想返回预定义类型的多个值(例如
int
、List
和DateTime
),并且您不想仅为此目的创建一个新类。http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx
out
keyword is good if you want to return multiple values of pre-defined types (for example anint
, aList<string>
and aDateTime
), and you don't want to create a new class just for this purpose.好吧,
让我们看一下此类函数的常见模式 -
TrySomething
。假设您有一个函数可能会成功地为您提供一个值,也可能不会,但您不会为此使用异常,因为您不想要开销或者这是一个常见特征。
然后,如果方法成功,通常会返回
true
,否则返回false
。但是你会把你的产出值放在哪里呢?一种可能的答案是使用如下所示的
out
参数:备注:
或者您可能会考虑使用
Tuple
并且实际上 F# 将上面的模式解释为自己生成这样一个元组。Ok,
let look at the usual pattern for this kind of function - the
TrySomething
.Suppose you have a function that might succeed giving you an value or not but you don't won't to use an exception for this because you don't want the overhead or it's a common trait.
Then you normaly return
true
if the method suceeded andfalse
if not. But where would you put your outputvalue to?One possible answer is using an
out
parameter like this:Remark:
Or you might consider using a
Tuple<bool,MyOutputType>
and indeed F# interpretes the pattern above as resulting in such a tuple by itself.