在 C# 中使用 'out' 关键字返回多个值

Returning Multiple Value with the 'out' Keyword in C#

我目前正在努力理解使用 'out' 关键字我们能够 return[=24] 的含义=] 多个值。例如来自msdn站点(https://msdn.microsoft.com/en-us/library/ee332485.aspx):“...以下示例使用了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(不使用 'return' 关键字)任何东西完全分配字段(类似于通过 ref 传递)。这与其他来源一致,他们指出使用 'out' 可以 return 多个值。我是不是误解了 return 这个词的上下文,还是我没有正确理解这个概念?

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

ref 将让编译器知道变量在进入函数之前应该已经初始化(这在您在该函数之前使用该变量并且现在想更改某些内容时很有用)。 out 将让编译器知道该对象已在其调用的函数内初始化。所以 ref 是双向的,out 是唯一的。

所以,是的,它实际上并没有 return 东西。但另一方面,它会为您的变量赋值,您的调用方法也会通过这些变量以新值结束。从本质上讲,您可以将其视为 return.

简而言之:

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

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

我还建议您阅读 Jon Skeet 关于参数传递的 this SO answer and the corresponding blog。它会给你很多关于这个概念的信息。正如 Jon Skeet 所说,使用 refout:

时要小心

It's basically a way of getting another return value, and should usually be avoided precisely because it means the method's probably trying to do too much.

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

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

  1. 该参数未用于输入。
  2. 参数的值肯定会在方法前赋值returns。

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

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

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

Error CS0177 The out parameter 'x' must be assigned to before control leaves the current method

Error CS0269 Use of unassigned out parameter '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}");

由于变量是在同一条语句中声明和初始化的,因此这种语法使某些东西变得更加明显"returned"。

同样在 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}");

你说得对,这个方法最多只能return(你所说的)一件事。或者,根据您的声明(return 类型 void),当方法完成时,它不会 return 任何调用代码。

如果您想从您的方法中获取多个值,您有两种选择:

  1. Return一个classstruct——那是一回事,但它可以包含多个值(那个东西的属性)

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

所以这有点取决于你所说的 return 的意思。在 return 值的意义上,您的示例代码 return 什么都没有(它是用 return 类型 void 声明的),如果您将其更改为具有 return 最多可以输入 return 一件事作为它的 return 值。但是在告诉调用代码在方法中做了什么的意义上,然后使用 out 参数你可以为多个值做到这一点。