为啥 out 参数不能有默认值?
Posted
技术标签:
【中文标题】为啥 out 参数不能有默认值?【英文标题】:Why can't an out parameter have a default value?为什么 out 参数不能有默认值? 【发布时间】:2014-07-18 23:10:03 【问题描述】:目前,当尝试在带有 out 参数的方法中执行某些操作时,我需要在方法体中分配 out 参数的值,例如
public static void TryDoSomething(int value, out bool itWorkerd)
itWorkerd = true;
if (someFavourableCondition)
// if I didn't assign itWorked variable before this point,
// I get an error: "Parameter itWorked must be assigned upon exit.
return;
// try to do thing
itWorkerd = // success of attempt to do thing
我希望能够设置itWorked
参数的默认值,这样我就不必在方法体中随意设置值。
public static void TryDoSomething(int value, out bool itWorkerd = true)
if (someFavourableCondition)
// itWorked was already assigned with a default value
// so no compile errors.
return;
// try to do thing
itWorkerd = // success of attempt to do thing
为什么不能为out
参数分配默认值?
【问题讨论】:
可能是因为它对调用者没有任何改变。您只是将赋值语句从方法的第一行移至参数列表。常规的默认参数会在所有调用者中分配(排序),因此它会改变外部行为。您要求的是几乎没有任何价值的语法糖。 方法的调用者如何表明他们希望应用默认值?现在想想,在你的方法完成后,调用者如何获取out
参数的值?
我认为这与能够忽略返回值一样有意义 - 很有意义。我想没有人认为这很重要(我认为不是),或者正如 Eric Lippert 经常说的那样,与它的附加值相比,实施起来成本太高。
我不同意您的断言,即您必须“任意设置值”。您签约为调用者提供Boolean
值。没有什么武断的。您对价值做出有意识的决定并提供它。如果您事先不知道该值应该是什么,那么在这种情况下您可能不应该使用out
。
相关:***.com/questions/2870544/…
【参考方案1】:
默认值可用于按值传递的参数。参数仍然传递给函数,但如果代码省略了参数,编译器会提供缺失值。
您提出的功能完全不同。您建议允许函数的实现者省略设置值,而不是调用者省略传递值。所以,这是一个完全不同的功能。为什么没有实施?以下是一些可能的原因:
-
没有人想过要实现此功能。
设计人员考虑了该功能并拒绝了它,因为它不够有用,不值得付出实施成本。
设计人员考虑了该功能并拒绝了它,因为它使用了与默认值参数相似的语法,但含义却截然不同。
【讨论】:
4.实现这样的功能可能是不可能的,因为运行时不知道此方法何时设置了值。当它获得与默认值不同的值时是否设置?或者如果out
参数获取默认值,它是否也设置了?实施者总是会忘记这个副作用。如果您考虑TryParse
-方法,则运行时应该必须了解方法是成功还是失败。自定义代码是不可能的。【参考方案2】:
即使它允许您提供这样的默认值,它仍然需要您为所有返回的参数分配值。所以你的默认值将被覆盖。
【讨论】:
【参考方案3】:方法参数上的 out 方法参数关键字导致方法引用传递给该方法的相同变量。当控制权传回调用方法时,对方法中的参数所做的任何更改都将反映在该变量中。 当您希望方法返回多个值时,声明 out 方法很有用。使用 out 参数的方法仍然可以返回值。一个方法可以有多个输出参数。 要使用 out 参数,参数必须显式地作为 out 参数传递给方法。 out 参数的值不会传递给 out 参数。 作为输出参数传递的变量不需要初始化。但是,必须在方法返回之前为 out 参数赋值。
编译器不允许你使用 out 参数作为默认参数,因为它违反了它的用例。如果你不将它传递给函数,你就不能在调用函数时使用它的值。
如果你可以像TryDoSomething(123)
这样调用下面的函数,那么就没有使用out参数,因为你将无法使用itWorked
的值
public static void TryDoSomething(int value, out bool itWorkerd = true)
if (someFavourableCondition)
// itWorked was already assigned with a default value
// so no compile errors.
return;
// try to do thing
itWorkerd = // success of attempt to do thing
【讨论】:
我认为asker不想在调用时省略参数。我认为询问者只是想避免必须为函数主体中的参数赋值。 问题是为什么out参数不能有默认值...所以解释一下为什么 并非如此。如您所描述的那样,询问者不希望在调用时省略参数。提问者想知道为什么没有为 out 参数实现与默认参数值完全不同的功能。呼叫者想在呼叫站点写TryDoSomething(123, out itWorked)
。但希望函数的实现能够省略设置 itWorked
的值,因此在这种情况下返回默认值。【参考方案4】:
默认参数值是传递给方法的参数的默认值in。您必须为 out 参数指定要传递的变量,以便获得返回值。
在某种程度上,您的第一个示例有一个默认值,设置在方法的开头。
【讨论】:
【参考方案5】:我很欣赏这并不能完全回答最初的问题,但我无法为 cmets 做出贡献。我自己也有同样的问题,所以发现自己在这里。
由于 C#7 现在允许 out 参数在调用范围内有效地声明为变量,因此分配默认值会很有用。
考虑以下简单方法:
private void ResolveStatusName(string statusName, out string statusCode)
statusCode = "";
if (statusName != "Any")
statusCode = statusName.Length > 1
? statusName.Substring(0, 1)
: statusName;
这样修改感觉很直观:
private void ResolveStatusName(string statusName, out string statusCode = "")
if (statusName != "Any")
statusCode = statusName.Length > 1
? statusName.Substring(0, 1)
: statusName;
其目的不仅是声明statusCode
值,还要定义它的默认值,但编译器不允许这样做。
【讨论】:
两种方法做的事情完全不同。在第一个中,您总是修改statusCode
并将其设置为空字符串,statusCode
永远不会等于“Any”。在第二个中,如果没有提交参数,则将其设置为空字符串 - 但如果您不传递参数,则以后不能在参考中使用它(out
将毫无意义)。否则,如果您认为 statusCode
会被更改为空字符串:statusCode
仍将保持为空。所以总而言之,这两种方法都是没有意义的——另外,你的代码中仍然没有理由说明默认值有什么意义。【参考方案6】:
如果您对使用“out”或“ref”的方法进行了两次调用,并且您希望避免将方法一分为二,如果其中一次调用未使用这些参数,则可以使用一种优雅的解决方案来避免来自编译器的“未使用该值”(或类似的东西)的警告是使用这样的东西:
method("hi", out _);
【讨论】:
以上是关于为啥 out 参数不能有默认值?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能使用模型方法作为默认值?无论如何,Python/Django 模型中的 self 是啥?