【问题标题】: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

标签: c# default-value out


【解决方案1】:

默认值可用于按值传递的参数。参数仍然传递给函数,但如果代码省略了参数,编译器会提供缺失值。

您提出的功能完全不同。您建议允许函数的实现者省略设置值,而不是调用者省略传递值。所以,这是一个完全不同的功能。为什么没有实施?以下是一些可能的原因:

  1. 没有人想过要实现此功能。
  2. 设计人员考虑了该功能并拒绝了它,因为它不够有用,不值得付出实施成本。
  3. 设计人员考虑了该功能并拒绝了它,因为它使用了与默认值参数相似的语法,但含义却截然不同。

【讨论】:

  • 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 _);

      【讨论】:

        猜你喜欢
        • 2013-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-01
        相关资源
        最近更新 更多