什么时候应该使用`out`参数而不是返回复杂类型?

时间:2009-04-19 16:53:12

标签: c# .net

我们何时应该在C#中使用out参数?

例如

bool TryGetValue(out object value);

VS

class ReturnType
{
      public bool Found {get;set;}
      public object Value {get;set;}
}

ReturnType TryGetValue();

除了减少代码行数外,何时应使用out参数以及何时应将其作为返回类型返回?

12 个答案:

答案 0 :(得分:4)

Out也可用于可能失败的操作(通常在启动Try *的方法中找到)。

E.g。 TryParse将返回一个bool,指示成功/失败,同时使用out值作为结果。这样可以避免抛出异常。

答案 1 :(得分:3)

你已经确切地说明了应该使用它的原因。为了降低代码复杂性。

if (TryGetValue(myObj))
{
    [...]
}

更整洁
Result tryGetValueResult = TryGetValue();
if (tryGetValueResult.Found)
{
    [...]
}

当结果需要作为引用类型时,它也可以节省垃圾。

答案 2 :(得分:3)

如果没有一般理由将多个值封装在一起,除了这个调用之外,那么创建一个单独的类型可能就在顶层。

另一方面,如果您有多个输出参数和一个逻辑上属于一起的返回值(例如,名字,姓氏,电话号码),那么创建一个合适的类型(例如“联系人”)可能是有意义的并返回。

TryGetValue选项的一个替代方法是使用可空值类型,如果有问题的值值类型。例如,int.TryParse可能有一个签名:

int? TryParse(string text)

(当然过载占用IFormatProvider)。

答案 3 :(得分:3)

它们在从构造函数返回值所需的(罕见)情况下非常有用。例如, Mutex 构造函数有一个布尔输出参数,该参数设置为指示是否创建了新的互斥锁,或者是否存在已存在名称的现有互斥锁。

答案 4 :(得分:2)

out关键字通过编译器执行一些操作。
调用者不必初始化参数。被调用者无法读取参数,但必须在退出方法之前写入。

更重要的是使意图可见,因为调用者在进行方法调用时必须指定out关键字

需要从方法中返回多个值(没有从对象[]中填充和去填充它们时)时,可以使用。 (喜欢从每个函数返回bSuccess的部分都会喜欢out关键字。)
在您发布的示例中.. TryParse的主要返回值是解析操作的成功。这就是它的返回值 - 但最可能的后续需求是获取解析后的对象(如果成功)。因此,TryParse不是让所有调用者都执行该步骤,而是通过将其作为out param来为您节省麻烦..因为它已经将其作为CanParse检查的一部分。

答案 5 :(得分:1)

输出参数通常是脆弱的一面。超越示例,一般地看待问题:Bill Wagner的书“更有效的C#”描述了一个非常聪明的方法,它也有详细描述here

以下代码适用于此实例。

public class Tuple<T1,T2>
{
  public T1 First {get;private set;}
  public T2 Second {get; private set;}
  Tuple(T1 first, T2 second)
  {
    First = first;
    Second = second;
  }
}


using ComplexPair = Tuple<bool,object>;

public class SomeOtherClass 
{
  public ComplexPair GetComplexType ()
  {
    ...
    return new ComplexPair(true, new object);

  }
}

答案 6 :(得分:1)

最好使用类似Option类型的东西作为可能不存在的返回类型的容器。这些在大多数函数语言中都很流行,比如Scala。适用于您只关心某些事情是成功还是失败的情况,而您并不关心原因。例如解析整数。

int num;  // mutable = bugprone
if (!int.TryParse(str, out num)) // branching = complexity
  num = someDefault;

使用Option类型,您可以定义一个包含可变丑陋的int解析器并返回一个干净的Option。如果只在一个地方,这可以降低您的复杂性。避免重复和变异。

  public Option<int> IntParse(string str) {
    int num;  // mutable
    if (!int.TryParse(str, out num))
      return Option.None<int>();
    else
      return Option.Some<int>(num);
  }

在其他地方使用:

int result = IntParse(someString).GetOrElse(defaultValue);

正如您所看到的,由于分支已隐藏,因此导致使用模式明显减少。

或者,如果你的函数必须返回两件事,那么有可能:

  • 功能过于复杂,应该拆分(做好一件事!)或
  • 返回值密切相关,应以新类型绑定在一起

想想的东西!

答案 7 :(得分:0)

如果object可以为null。 不需要实例化。

答案 8 :(得分:0)

我会投票使用返回类型。尽管C#不是一种函数式语言,但我认为瞄准函数式编程风格是件好事。不是为了学术上的纯洁,而是为了实用的好处,每个功能的行为都是非神秘的,没有副作用。

答案 9 :(得分:0)

如果您希望函数只返回对现有对象的引用或创建新对象,则只应使用out参数。

答案 10 :(得分:0)

在我的公开场合都是正确的,但我发现返回一个更优雅的复杂类型,特别是如果它是泛型类型

ReturnType<T>

这提供了有关该值将会是什么的更多信息,因此您不会猜测Value原始类型并进行转换。

答案 11 :(得分:-3)

我想保留成功指标的返回值。要么是成功的简单的真/假,要么是更复杂的东西,比如0表示成功,还有其他值表示错误是什么。

这意味着程序员可以测试您编写的每个函数是否成功。 (当然,并非所有人都愿意,但可以

然后需要 out 参数来从函数中检索值。

相关问题