如何指示方法不成功

时间:2020-03-06 15:01:16  来源:igfitidea点击:

我有几种类似的方法,例如。 CalculatePoint(...)和CalculateListOfPoints(...)。有时,它们可能不会成功,并且需要向呼叫者表明这一点。对于返回通用列表的CalculateListOfPoints,我可以返回一个空列表,并要求调用者进行检查。但是Point是一个值类型,所以我不能在那里返回null。

理想情况下,我希望这些方法"看起来"相似。一种解决方案是将它们定义为

public Point CalculatePoint(... out Boolean boSuccess);
public List<Point> CalculateListOfPoints(... out Boolean boSuccess);

或者返回一个点?为CalculatePoint,并返回null表示失败。但这意味着必须强制转换为不可为空的类型,这似乎过多。

另一种方法是返回布尔值boSuccess,将结果(点或者列表)作为"输出"参数,然后将它们命名为TryToCalculatePoint或者其他东西。

什么是最佳做法?

编辑:我不想使用异常进行流控制!有时可能会失败。

解决方案

我会说最佳实践是返回值表示成功,而异常则表示失败。

在我们提供的示例中,我看不出有任何理由在发生故障时不应使用异常。

就个人而言,我想我会使用与TryParse()相同的想法:使用out参数输出实际值,并返回一个布尔值,指示调用是否成功

public bool CalculatePoint(... out Point result);

我不喜欢将异常用于"正常"行为(如果我们希望该功能不适用于某些条目)。

另一种选择是引发异常。但是,我们通常只想在"例外情况"中引发例外。

如果失败的情况很普遍(而不是例外),那么我们已经列出了两个选择。编辑:项目中可能有一个约定,即如何处理此类非异常情况(无论是应返回成功还是返回对象)。如果没有现有约定,那么我同意lucasbfr并建议我们返回成功(这与TryParse(...)的设计方式相同)。

在某些情况下(尤其是在编写服务器时),使用异常是个坏主意。我们将需要两种方法。还要查看字典类,以了解我们应该做什么。

// NB:  A bool is the return value. 
//      This makes it possible to put this beast in if statements.
public bool TryCalculatePoint(... out Point result) { }

public Point CalculatePoint(...)
{
   Point result;
   if(!TryCalculatePoint(... out result))
       throw new BogusPointException();
   return result;
}

两全其美!

布尔TrySomething()至少是一种实践,对于.net的解析方法来说还可以,但是我认为我总体上不喜欢它。

抛出异常通常是一件好事,尽管不应将其用于在许多正常情况下可能会发生的情况,并且它会带来相关的性能成本。

在大多数情况下,当我们不希望发生异常时,可以返回null。

但是,方法有点程序性,如何创建类似PointCalculator类的东西,并在构造函数中将所需数据作为参数?然后,在其上调用CalculatePoint,并通过属性(Point和Success的单独属性)访问结果。

我使用的模型与MS在各种类的TryParse方法中使用的模型相同。

原始代码:
公共点CalculatePoint(... out布尔boSuccess);
公共列表CalculateListOfPoints(... out布尔boSuccess);

会变成
公共布尔CalculatePoint(... out(或者ref)Point CalculatedValue);
公共布尔CalculateListOfPoints(... out(或者ref)列表CalculatedValues);

基本上,我们将成功/失败作为返回值。

我们不希望在发生某些事情时抛出异常,因为@Kevin声明的异常是针对特殊情况的。

我们应该返回"失败"所预期的内容,通常我选择的不良回报为null。

方法的文档应告知用户在不计算数据时会发生什么。

总结一下,我们可以采取几种方法:

  • 当返回类型是值类型(例如Point)时,请使用C#的Nullable功能并返回Point? (aka Nullable),这样我们仍然可以在失败时返回null
  • 发生故障时引发异常。关于什么是"异常"和什么不是"例外"的整个争论/讨论是有争议的,这是API,我们可以决定什么是特殊的行为。
  • 采用与Microsoft在Int32这样的基本类型中实现的模型相似的模型,提供CalculatePoint和TryCalculatePoint(int32.Parse和int32.TryParse),并抛出一个错误并返回一个布尔值。
  • 从方法中返回具有两个属性bool Success和GenericType Value的通用结构。

根据情况,我倾向于结合使用返回null或者引发异常的组合,因为它们对我来说似乎"最干净",并且最适合与我工作的公司的现有代码库。因此,我个人的最佳实践是方法1和2.

它主要取决于方法的行为及其用法。

如果失败是常见且不严重的,则让方法返回一个指示成功的布尔值,并使用out参数来传达结果。在哈希中查找键,在没有可用数据时尝试在非阻塞套接字上读取数据,所有这些示例都属于该类别。

如果意外失败,请直接返回结果并传达异常情况下的错误。最好以只读方式打开文件,然后连接到TCP服务器。

有时两种方式都有意义...

他们为什么会失败?如果是由于调用者已完成的操作(即提供的参数),则抛出ArgumentException是完全合适的。避免异常的Try [...]方法很好。

我认为提供一个引发异常的版本是一个好主意,这样,如果希望他们总是提供良好的数据的调用者犯错了,则会收到适当的强烈信息(即异常)。

如果失败是由于特定原因,那么我认为可以返回null或者bool并具有out参数。但是,如果无论失败如何都返回null,那么我不建议我们这样做。异常提供了丰富的信息,包括为什么某些原因失败的原因,如果返回的所有结果都是null,那么如何知道是否由于数据错误,内存不足或者其他怪异行为。

即使在.net中,TryParse都有一个Parse兄弟,因此我们可以根据需要获取异常。

如果我提供了TrySomething方法,那么我还将提供Something方法,该方法在发生故障时会引发异常。然后由调用者决定。

我们曾经编写了一个完整的Framework,其中所有公共方法或者返回true(成功执行),或者返回false(发生错误)。如果需要返回值,则使用输出参数。与普遍的看法相反,这种编程方式实际上简化了许多代码。

使用Point,可以在失败的情况下将Point.Empty作为返​​回值发送回去。现在,所有这些真正要做的就是为X和Y值返回一个带有0的点,因此,如果这可以是一个有效的返回值,我将尽量避免这样做,但是如果方法永远不会返回(0,0) ,那么我们可以使用它。

返回Point.Empty。当我们要检查结构创建是否成功时,这是一个.NET设计模式,可以返回一个特殊字段。尽可能避免使用掉参数。

public static readonly Point Empty

我正在尝试的一种模式正在返回Maybe。它具有TryParse模式的语义,但与错误时返回null模式相似。

我尚未说服其中一种方法,但我将其提供给我们集体考虑。这样做的好处是,不需要在方法调用之前定义变量即可将out参数保存在方法的调用位置。它也可以通过Errors或者Messages集合进行扩展,以指示失败的原因。

Maybe类看起来像这样:

/// <summary>
/// Represents the return value from an operation that might fail
/// </summary>
/// <typeparam name="T"></typeparam>
public struct Maybe<T>
{
    T _value;
    bool _hasValue;

    public Maybe(T value)
    {
        _value = value;
        _hasValue = true;
    }

    public Maybe()
    {
        _hasValue = false;
        _value = default(T);
    }

    public bool Success
    {
        get { return _hasValue; }
    }

    public T Value
    {
        get 
            { // could throw an exception if _hasValue is false
              return _value; 
            }
    }
}

抱歉,我只记得Nullable类型,应该看看。我不太确定那是什么开销。