哪个更好,返回值还是输出参数?

Vim*_*987 140 c# reference

如果我们想从方法中获取值,我们可以使用返回值,如下所示:

public int GetValue(); 
Run Code Online (Sandbox Code Playgroud)

要么:

public void GetValue(out int x);
Run Code Online (Sandbox Code Playgroud)

我真的不明白它们之间的差异,所以,不知道哪个更好.你能解释一下这个吗?

谢谢.

Jon*_*eet 151

当方法没有任何其他东西可以返回时,返回值几乎总是正确的选择.(事实上,我不能想到这里我想任何情况下,曾经想要一个空白方法与out参数,如果我当初的选择.C#7的Deconstruct方法语言支持的解构作为一个非常,非常罕见的例外.)

除了其他任何东西,它会阻止调用者分别声明变量:

int foo;
GetValue(out foo);
Run Code Online (Sandbox Code Playgroud)

VS

int foo = GetValue();
Run Code Online (Sandbox Code Playgroud)

Out值也会阻止方法链接,如下所示:

Console.WriteLine(GetValue().ToString("g"));
Run Code Online (Sandbox Code Playgroud)

(实际上,这也是属性设置器的问题之一,这就是构建器模式使用返回构建器的方法的原因,例如myStringBuilder.Append(xxx).Append(yyy).)

另外,out参数稍微难以用于反射,通常也会使测试更加困难.(通常会花费更多精力来模拟返回值而不是输出参数).基本上没有什么我能想到的,他们更容易 ......

返回值FTW.

编辑:就发生的事情而言......

基本上,当您传入一个"out"参数的参数时,您必须传入一个变量.(数组元素也被归类为变量.)您调用的方法在其堆栈上没有参数的"新"变量 - 它使用您的变量进行存储.变量中的任何更改都会立即可见.这是一个显示差异的示例:

using System;

class Test
{
    static int value;

    static void ShowValue(string description)
    {
        Console.WriteLine(description + value);
    }

    static void Main()
    {
        Console.WriteLine("Return value test...");
        value = 5;
        value = ReturnValue();
        ShowValue("Value after ReturnValue(): ");

        value = 5;
        Console.WriteLine("Out parameter test...");
        OutParameter(out value);
        ShowValue("Value after OutParameter(): ");
    }

    static int ReturnValue()
    {
        ShowValue("ReturnValue (pre): ");
        int tmp = 10;
        ShowValue("ReturnValue (post): ");
        return tmp;
    }

    static void OutParameter(out int tmp)
    {
        ShowValue("OutParameter (pre): ");
        tmp = 10;
        ShowValue("OutParameter (post): ");
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

Return value test...
ReturnValue (pre): 5
ReturnValue (post): 5
Value after ReturnValue(): 10
Out parameter test...
OutParameter (pre): 5
OutParameter (post): 10
Value after OutParameter(): 10
Run Code Online (Sandbox Code Playgroud)

差异在于"后"步骤 - 即在局部变量或参数被更改之后.在ReturnValue测试中,这对静态value变量没有影响.在OutParameter测试中,value变量由行更改tmp = 10;

  • 你让我相信回报价值要好得多:).但我仍然想知道"深入"会发生什么.我的意思是,返回值和out参数在创建,分配和返回的方式上有所不同吗? (2认同)
  • TryParse 是使用输出参数适当且干净的最佳示例。尽管我在特殊情况下使用过它,例如 if (WorkSucceeded(out List<string>Errors) ,它与 TryParse 的模式基本相同 (2认同)
  • 一个糟糕的无益答案.正如[本问题](http://stackoverflow.com/questions/11212759/c-sharp-out-parameters-vs-returns)上的评论所述,out参数有几个有用的优点.out与return之间的偏好应取决于具体情况. (2认同)
  • @aaronsnoswell:哪些准确的评论?请记住,`Dictionary.TryGetValue`的例子在这里不适用,因为那不是一个void方法.你能解释为什么你想要一个'out`参数**而不是**的返回值吗?(即使对于`TryGetValue`,我更喜欢一个包含所有输出信息的返回值.请参阅NodaTime的`ParseResult <T>`以获取我如何设计它的示例.) (2认同)
  • @Jim:我想我们不得不同意不同意.虽然我看到了你的观点,即用这个来锤击人们的头脑,但它也使那些不知道他们正在做什么的人不那么友好.关于异常而不是返回值的好处是,你不能轻易地*忽略它并继续进行,好像什么也没发生......而同时使用返回值和`out`参数,你可以不做任何有价值的东西. (2认同)

pyr*_*lus 26

什么更好,取决于您的具体情况.存在的一个原因out是为了便于从一个方法调用返回多个值:

public int ReturnMultiple(int input, out int output1, out int output2)
{
    output1 = input + 1;
    output2 = input + 2;

    return input;
}
Run Code Online (Sandbox Code Playgroud)

因此,根据定义,一个不是另一个.但通常你会想要使用简单的回报,除非你有上述情况.

编辑: 这是一个示例,说明关键字存在的原因之一.以上内容绝不是最佳实践.

  • 我同意@Cloud。仅仅因为它不是最好的方式并不意味着它不应该存在。 (3认同)
  • 我不同意这一点,你为什么不返回一个包含4个整数的数据结构?这真令人困惑. (2认同)
  • 不会编译?那为什么呢?这个示例可以完美地编译。拜托,我提供了一个示例,说明为什么存在特定语法/关键字,而不是最佳实践课程。 (2认同)

Mar*_*eck 23

您通常应该更喜欢返回值而不是out param.如果你发现你自己编写需要做两件事的代码,那么params就是一种诡计.一个很好的例子是Try模式(例如Int32.TryParse).

让我们考虑两种方法的调用者必须做什么.对于第一个例子,我可以写这个......

int foo = GetValue();
Run Code Online (Sandbox Code Playgroud)

请注意,我可以声明一个变量,并通过您的方法在一行中分配它.对于第二个例子,它看起来像这样......

int foo;
GetValue(out foo);
Run Code Online (Sandbox Code Playgroud)

我现在被迫在前面声明我的变量并将我的代码写成两行.

更新

在询问这些类型的问题时,一个好看的地方是.NET Framework设计指南.如果您有图书版本,那么您可以看到Anders Hejlsberg和其他人关于此主题的注释(第184-185页),但在线版本在这里......

http://msdn.microsoft.com/en-us/library/ms182131(VS.80).aspx

如果你发现自己需要从API中返回两个东西,那么将它们包装在struct/class中会比out param更好.


小智 12

使用out尚未提及的参数有一个原因:调用方法有义务接收它.如果您的方法产生一个调用者不应该丢弃的值,则out强制调用者专门接受它:

 Method1();  // Return values can be discard quite easily, even accidentally

 int  resultCode;
 Method2(out resultCode);  // Out params are a little harder to ignore
Run Code Online (Sandbox Code Playgroud)

当然,呼叫者仍然可以忽略outPARAM,但你叫他们的注意.

这是一种罕见的需求; 更常见的情况是,您应该使用异常来处理真正的问题,或者返​​回具有"FYI"状态信息的对象,但是在某些情况下这很重要.


Sco*_*wan 8

它主要是偏好

我更喜欢返回,如果你有多个返回,你可以将它们包装在Result DTO中

public class Result{
  public Person Person {get;set;}
  public int Sum {get;set;}
}
Run Code Online (Sandbox Code Playgroud)


Bri*_*ian 5

您几乎应该总是使用返回值.' out'参数会对许多API,组合等产生一些摩擦.

想到的最值得注意的异常是当你想要返回多个值时(.Net Framework在4.0之前没有元组),例如TryParse模式.


Rob*_*Day 5

您只能有一个返回值,而可以有多个out参数。

在这种情况下,您只需要考虑参数。

但是,如果您需要从方法中返回多个参数,则可能要查看从OO方法返回的内容,并考虑是否最好返回带有这些参数的对象或结构。因此,您又回到了返回值。