在什么情况下'out'参数有用(不能使用'ref'代替)?

时间:2010-06-27 19:00:47

标签: c# out-parameters ref-parameters

据我所知,out参数的唯一用途是调用者可以从单个方法调用中获取多个返回值。但我们也可以使用ref参数获取多个结果值!

还有其他情况,out参数可能有用,而我们无法使用ref参数吗?

谢谢。

6 个答案:

答案 0 :(得分:29)

是的 - refout之间的区别在于明确分配:

  • 在方法调用之前,调用方必须明确分配out参数 。在正常返回之前(即没有例外),必须在方法中明确分配 。然后,在调用之后,在调用者中明确分配变量。

  • 在方法调用之前,调用方必须明确分配ref参数 必须在方法中分配不同的值。

因此,我们希望将int.TryParse(string, out int)改为使用ref。通常调用代码如下所示:

int value;
if (int.TryParse(text, out value))
{
    // Use value
}
else
{
    // Do something else
}

现在,如果我们使用ref,我们必须在通话前给value一个值,例如:

int value = 0;
if (int.TryParse(text, ref value))
{
    // Use value
}
else
{
    // Do something else
}

显然这不是巨大的差异 - 但它会给人一种错误的印象。我们正在分配一个我们无意使用的值,这对于可读性来说并不是一件好事。 out参数表示值从方法中出来(假设没有异常)并且您不需要具有值来开始。

我为C#5提出的一些建议(我不知道它是否会被占用)是一个带有out参数的方法应该能够被视为一种方法返回一个值元组。结合对元组的更好支持,这意味着我们可以做到这样的事情:

var (ok, value) = int.TryParse(text);

在这种情况下,okvalue将分别隐式输入boolint。这样就可以清楚地了解方法(text)以及即将发布的内容(两条信息:okvalue)。

如果int.TryParse使用了ref参数,那将无法使用 - 因为编译器无法知道它是否实际关心的初始值ref参数。

答案 1 :(得分:8)

您可以通过以下方式查看参数:

  • 正常参数 in 参数:
    一个值可以通过这样的参数进入函数;因此必须初始化。

  • ref参数是 in-out 参数:
    一个值可以通过这样的参数进出函数。由于前者,它也必须初始化。

  • out参数是 out 参数:
    一个值只能通过这样的参数从函数返回;因此,它不需要初始化。

通过研究微软的COM技术,我想出了这种查看ref / out参数的方法。 IDL(接口描述语言)用于描述COM组件接口,使用IDL,参数通过inoutinout声明符进行扩充。我怀疑.NET和C#部分继承了COM中的这些声明符,虽然名称略有不同(ref而不是inout)。

使用COM时,out参数经常用于检索接口方法的实际返回值,因为“实际”返回值通常已用于返回HRESULT成功/错误代码。

使用.NET,我认为out参数的重要性要低得多,即使在你想从方法中返回多个值的情况下(在这些情况下你可以返回复杂的对象或Tuple

答案 2 :(得分:4)

一个重要的区别是:

  

作为out参数传递的变量   无需初始化。然而   out参数必须赋值   在方法返回之前。

(ref参数不需要这个)

来源:http://msdn.microsoft.com/en-us/library/t3c3bfhx(VS.71).aspx

答案 3 :(得分:2)

当您需要方法的多个结果值时,out参数非常有用。从技术上讲,您可以使用ref参数来实现相同的目标,但out参数可以更好地传达意图。当您使用ref时,不清楚为什么这样做而不是使用out或代替使用函数结果。据推测,您打算更改传递的值,但是为什么要更改它并不是简单地从函数签名中清楚。

答案 4 :(得分:2)

我认为一个很好的例子是int.TryParse()

http://msdn.microsoft.com/en-us/library/f02979c7.aspx

out 优于 ref 的主要原因是您在调用(甚至隐式)之前无需为返回var指定虚拟值。< / p>

所以 out 告诉你和编译器:“这个var将在方法中分配。而var的初始值,如果有的话,甚至都不会被查看。”

答案 5 :(得分:0)

两者之间的主要区别在于,如果我们使用 ref ,那么我们必须在调用之前对其进行初始化,并且我们可以选择为 ref 变量赋值在我们的方法中。

但是对于 out 方法,我们不必显式初始化它们,但在我们的方法中,我们必须为它分配一些值,否则它们将产生编译时错误。