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

C# 什么时候应该使用'out'参数而不是返回复杂类型?,c#,.net,C#,.net,什么时候应该在C#中使用out参数 比如说 bool TryGetValue(out object value); vs 除了减少代码行数外,何时应该使用out参数,何时应该将其作为返回类型返回?如果对象可以为null。 那么就不需要重新安装了。您已经明确了使用它的原因。降低代码复杂度 if (TryGetValue(myObj)) { [...] } 他比我整洁 Result tryGetValueResult = TryGetValue(); if (tryGetValueRes

什么时候应该在C#中使用
out
参数

比如说

bool TryGetValue(out object value);
vs

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

如果对象可以为null。
那么就不需要重新安装了。

您已经明确了使用它的原因。降低代码复杂度

if (TryGetValue(myObj))
{
    [...]
}
他比我整洁

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

当结果需要是引用类型时,它还可以节省垃圾。

如果没有一般理由将多个值封装在一起(除了此调用),那么创建一个单独的类型可能太过分了

另一方面,如果您有多个out参数和一个返回值,并且这些参数和返回值在逻辑上都属于同一个类型(例如名字、姓氏、电话号码),那么创建一个适当的类型(例如“联系人”)并返回该类型可能是有意义的

TryGetValue
选项的一种替代方法是,如果所讨论的值是值类型,则使用可为空的值类型。例如,int.TryParse可能有以下签名:

int? TryParse(string text)

(当然,重载使用了
IFormatProvider

它们在(罕见的)需要从构造函数返回值的情况下非常有用。例如,Mutex构造函数有一个boolean out参数,该参数被设置为指示是否创建了新的Mutex,或者是否已存在具有名称的现有Mutex。

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


例如,TryParse将返回一个bool,指示成功/失败,同时使用out值作为结果。这避免了抛出异常。

我会投票赞成使用返回类型。尽管C#不是函数式语言,但我认为以函数式编程风格为目标是很好的。不是为了学术上的纯粹,而是为了实用上的好处,每个函数的行为都不神秘,没有副作用。

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

我想为成功指标保留返回值。简单的true/false表示成功,或更复杂的值,如0表示成功,以及其他指示错误的值

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


这就需要out参数从函数中检索值。

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

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

需要从方法返回多个值时,可以使用out(无需从对象[]填充和取消填充它们)。(喜欢从每个函数返回bsucces的部分会喜欢out关键字。)

在您发布的示例中。。TryParse的主要返回值是解析操作的成功。这就是它的返回值——但是如果成功的话,最可能的后续需要是获得解析的对象。因此,TryParse没有让所有呼叫者都执行该步骤,而是将其作为out参数提供,从而为您省去了麻烦。。因为它已经将此作为CanParse检查的一部分进行了检查。

输出参数通常是脆弱的。超越这个例子,从总体上看这个问题:比尔·瓦格纳的书《更有效的C#》描述了一个相当聪明的方法,它也被详细描述了

下面的代码将在该实例中工作

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);

  }
}
公共类元组
{
公共T1第一个{get;私有集;}
公共T2秒{get;私有集;}
元组(T1第一,T2第二)
{
第一=第一;
秒=秒;
}
}
使用ComplexPair=Tuple;
公共类其他类
{
公共ComplexPair GetComplexType()
{
...
返回新的ComplexPair(true,新对象);
}
}

在我的openion中,两者都是正确的,但是我发现返回复杂类型更优雅,特别是如果它是泛型类型

ReturnType<T>
ReturnType

这提供了有关期望值的更多信息,因此您不会猜测原始类型的值并进行转换。

最好使用选项类型之类的内容作为可能缺少的返回类型的容器。这些在大多数函数式语言(如Scala)中都很普遍。适用于您只关心某件事情是否成功,而不关心原因的情况。e、 解析整数

int num;  // mutable = bugprone
if (!int.TryParse(str, out num)) // branching = complexity
  num = someDefault;
使用optiontype,您可以定义一个int解析器,它封装了可变的丑陋并返回一个干净的选项。这减少了您的复杂性,因为它只在一个地方。避免重复和变异

  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);
  }
正如您所看到的,这导致了一个可测量的不太复杂的使用模式,因为分支已被隐藏

或者,如果函数必须返回两个内容,则有可能:

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

要考虑的东西

这里有一个相关的线索:代码数量的减少与可扩展性和优雅性之间有一条细线。假设有两个以上的out参数,那么最好使用as-return-typesideeffects,而神秘意味着函数做了一些你意想不到的事情。如果您在out位置传递某个内容,这不正是您所期望的吗?-1-in.NET在一般情况下,您应该更喜欢异常而不是返回代码。有时可能会有一个功能,你前
  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);