C# 返回值和输出参数哪个更好?

C# 返回值和输出参数哪个更好?,c#,reference,C#,Reference,如果我们想从方法中获取一个值,我们可以使用返回值,如下所示: public int GetValue(); Console.WriteLine(GetValue().ToString("g")); 或: 我真的不明白它们之间的区别,所以,不知道哪一个更好。你能给我解释一下吗 谢谢。我更喜欢以下内容,而不是这个简单示例中的任何一个 public int Value { get; private set; } 但是,它们都非常相似。通常,只有当需要从方法传回多个值时,才会使用

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

public int GetValue(); 
Console.WriteLine(GetValue().ToString("g"));
或:

我真的不明白它们之间的区别,所以,不知道哪一个更好。你能给我解释一下吗


谢谢。

我更喜欢以下内容,而不是这个简单示例中的任何一个

public int Value
{
    get;
    private set;
}
但是,它们都非常相似。通常,只有当需要从方法传回多个值时,才会使用“out”。如果您想在方法中发送一个值,可以选择“ref”。我的方法是最好的,如果您只返回一个值,但如果您想传递一个参数并返回一个值,则可能会选择您的第一个选择。

这是首选

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

public class Result{
  public Person Person {get;set;}
  public int Sum {get;set;}
}

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

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

    return input;
}
因此,从定义上讲,一个并不比另一个好。但通常你会想要使用一个简单的报税表,除非你有上述情况

编辑:
这是一个示例,演示了关键字存在的原因之一。以上内容决不是最佳实践。

您几乎应该始终使用返回值。”<代码>输出'参数会对许多API、组合性等产生一些摩擦

想到的最值得注意的例外是,当您想要返回多个值时(.Net Framework直到4.0才有元组),例如使用
TryParse
模式。

当方法没有任何其他可返回的内容时,返回值几乎总是正确的选择。(事实上,如果我可以选择的话,我想不出任何情况下我会想要一个带有
out
参数的void方法。C#7的
Deconstruct
语言支持的解构方法是这条规则非常非常罕见的例外。)

除此之外,它还可以阻止调用方单独声明变量:

int foo;
GetValue(out foo);
vs

Out值还可以防止像这样的方法链接:

public int GetValue(); 
Console.WriteLine(GetValue().ToString("g"));
(事实上,这也是属性设置器的问题之一,这也是构建器模式使用返回构建器的方法的原因,例如
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): ");
    }
}
结果:

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

差异出现在“post”步骤,即局部变量或参数更改后。在ReturnValue测试中,这对静态
变量没有影响。在输出参数测试中,
变量通过
tmp=10行改变

通常,您应该更喜欢返回值而不是out参数。如果您发现自己编写的代码需要做两件事,那么Out参数是一个必要的缺点。一个很好的例子是Try模式(比如Int32.TryParse)

让我们考虑一下你的两个方法的调用方需要做什么。对于第一个例子,我可以写这个

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

int foo;
GetValue(out foo);
我现在被迫提前声明变量,并在两行上编写代码

更新

当问这些类型的问题时,最好看一下.NET Framework设计指南。如果你有书的版本,那么你可以看到安德斯·赫兹伯格和其他人关于这个主题的注释(第184-185页),但是在线版本在这里


如果您发现自己需要从一个API返回两个东西,那么将它们包装在一个结构/类中比使用out参数要好。

它们都有不同的用途,编译器不会对它们进行相同的处理。如果方法需要返回值,则必须使用return。Out用于方法需要返回多个值的地方


如果使用return,则数据首先写入方法堆栈,然后写入调用方法的堆栈。而在out的情况下,它直接写入调用方法堆栈。不确定是否还有任何差异。

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

你只需要考虑这些情况下的参数。


但是,如果需要从方法返回一个以上的参数,您可能希望查看从OO方法返回的内容,并考虑如果返回具有这些参数的对象或结构是否更好。因此,您又回到了返回值。

没有真正的区别。Out参数在C#中,以允许方法返回多个值,仅此而已

然而,有一些细微的差异,但其中没有一个是真正重要的:

使用out参数将强制您使用以下两行:

int n;
GetValue(n);
使用返回值时,您可以在一行中完成此操作:

int n = GetValue();

另一个区别(仅适用于值类型,并且仅适用于C#不内联函数的情况)是,当函数返回时,使用return value必然会生成值的副本,而使用OUT参数则不一定如此。

正如其他人所说:return value,
 Method1();  // Return values can be discard quite easily, even accidentally

 int  resultCode;
 Method2(out resultCode);  // Out params are a little harder to ignore
public BookList Find(string key)
{
   BookList book; //BookList is a model class
   _books.TryGetValue(key, out book) //_books is a concurrent dictionary
                                     //TryGetValue gets an item with matching key and returns it into book.
   return book;
}
var result = DoThing();
if (result.Success)
{
    result = DoOtherThing()
    if (result.Success)
    {
        result = DoFinalThing()
        if (result.Success)
        {
            success = true;
        }
    }
}
var result;
if (DoThing(out result))
{
    if (DoOtherThing(out result))
    {
        if (DoFinalThing(out result))
        {
            success = true;
        }
    }
}