为啥 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 参数不能有默认值?的主要内容,如果未能解决你的问题,请参考以下文章

golang函数中的参数为啥不支持默认值

golang函数中的参数为啥不支持默认值

HSQLDB - 为啥我不能将默认值设置为 -1

为啥我不能使用模型方法作为默认值?无论如何,Python/Django 模型中的 self 是啥?

prisma:为啥我不能将“null”设置为可空列的默认值?

在JAVA中能给方法参数赋默认值吗