【问题标题】:Returning Multiple Value with the 'out' Keyword in C#在 C# 中使用“out”关键字返回多个值
【发布时间】:2017-09-02 20:02:09
【问题描述】:

我目前正在努力理解当它声明使用 'out' 关键字我们能够返回多个值时它的含义。例如,来自 msdn 站点 (https://msdn.microsoft.com/en-us/library/ee332485.aspx):“...以下示例通过单个方法调用使用 out to return 三个变量。”

class OutReturnExample
{
    static void Method(out int i, out string s1, out string s2)
    {
        i = 44;
        s1 = "I've been returned";
        s2 = null;
    }
    static void Main()
    {
        int value;
        string str1, str2;
        Method(out value, out str1, out str2);
        // value is now 44
        // str1 is now "I've been returned"
        // str2 is (still) null;
    }
}

我不确定我是否只是没有正确阅读描述,但似乎 Method() 实际上并没有返回(不使用'return'关键字)任何东西,并且基本上分配了字段(同样通过参考)。这与他们声明使用“out”可以返回多个值的其他来源一致。我是误解了返回词的上下文还是我没有正确理解这个概念?

【问题讨论】:

  • out 关键字意味着在方法调用之后,这些变量必须分配一些东西。
  • 在语义上等价于return。你调用一个方法,你的“输出”变量填充了结果,就像你调用一个返回类型的方法并让一个变量填充结果一样。
  • out 关键字意味着外部范围内的所有值都将被“创建”和“分配”。您可以说它们已被退回,因为 out 声明合同必须在当前方法中更改这些值。
  • 你可能误解了返回词的上下文 =) 这不是“传递一些值” - 它是“返回执行 from 方法” .你的第一个void 方法可以重写为static void Merhod(...) { ... ; s2 = null; return; } 编译器允许你在最后省略return,因为很明显你正在从该方法返回,因为没有什么可做的了。

标签: c# return keyword terminology out


【解决方案1】:

该方法确实没有返回您正确注意到的值。 refout 都使用引用。

ref 会让编译器知道变量在进入函数之前应该已经被初始化(当你在函数之前使用变量并且现在想改变一些东西时这很有用)。 out 会让编译器知道对象在它调用的函数内部被初始化。所以ref 是双向的,out 是唯一的。

所以,是的,它实际上并没有返回任何东西。但另一方面,它会为您的变量分配值,您的调用方法也会通过这些变量获得新值。从本质上讲,您可以将其视为回报。

简而言之:

  • ref 参数 - 这些具有与 C++ 参考相同的功能 参数和

  • out 参数 - 这些允许从方法传回数据,但不允许 进入方法。

我还建议您阅读 Jon Skeet 的 this SO answercorresponding blog 关于参数传递的内容。它会给你很多关于这个概念的信息。正如 Jon Skeet 所说,使用 refout 时要小心:

这基本上是一种获取另一个返回值的方法,并且应该 通常要避免,因为这意味着该方法可能 试图做太多事情。

【讨论】:

  • @xanatos 我改写了它以使其更清楚。感谢您指出!
【解决方案2】:

它使用术语return 是为了它的语义,而不是它作为关键字的用途。

从语义上讲,当您使用 out 关键字时,您指定了两件事:

  1. 该参数不用于输入。
  2. 在方法返回之前,参数的值肯定会被赋值。

在这方面,out 参数是从方法返回的值。

编译器会强制执行这些语义。以下代码将生成几个警告:

public static void Test(out int x)
{
    Console.WriteLine(x);
}

错误 CS0177 必须在控制离开当前方法之前分配输出参数“x”

错误 CS0269 使用未分配的输出参数“x”

请注意,C#7(又名 Visual Studio 2017)将允许您在方法调用中声明变量。

给定:

public static void  Test(out int x, out int y)
{
    x = 1;
    y = 2;
}

C# 7 允许您这样做:

Test(out int x, out int y);
Console.WriteLine($"x = {x}, y = {y}");

这种语法使某些东西被“返回”更加明显,因为变量是在同一个语句中声明和初始化的。

同样在 C# 7 中,您可以使用元组而不是 out,我认为这更好(并且使用 lambda 效果更好!)。

上面的例子可以用C#7重写如下:

public static (int x, int y)  Test()
{
    int x = 1;
    int y = 2;
    return (x, y);
}

那么你可以这样做:

(int x, int y) = Test();
Console.WriteLine($"x = {x}, y = {y}");

【讨论】:

    【解决方案3】:

    你是对的,该方法最多只能返回(在你所说的意义上)一件事。或者,根据您的声明(返回类型为void),当方法完成时,它根本不会向调用代码返回任何内容。

    如果你想从你的方法中获取多个值,你有几个选择:

    1. 返回 classstruct — 这是一回事,但它可以包含多个值(该事物的属性)

    2. 根据您的示例,使用 out 修饰符将一些参数传递到方法中。 outref 类似,因为您的方法处理的是实际值,而不是它的副本。但与ref 不同的是,该方法必须在方法完成之前将值分配给标记为out 的任何参数(如果没有,您将收到编译器错误)。您可以有多个带有out 修饰符的参数。

    所以这有点取决于你所说的 return 是什么意思。在返回值的意义上,您的示例代码什么都不返回(它被声明为返回类型void),如果您将它更改为具有返回类型,它最多可以返回一个东西作为它的返回值。但是在告诉调用代码在方法中做了什么的意义上,然后使用out 参数,您可以为多个值执行此操作。

    【讨论】:

      猜你喜欢
      • 2014-12-16
      • 2011-12-04
      • 1970-01-01
      • 2015-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多