如何指示方法不成功

本文关键字:方法 不成功 指示 何指示 | 更新日期: 2023-09-27 17:48:54

我有几种类似的方法,例如CalculatePoint(…)和CalculateListOfPoints(。对于CalculateListOfPoints,它返回一个通用列表,我可以返回一个空列表,并要求调用方对此进行检查;然而,Point是一个值类型,所以我不能在那里返回null。

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

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

或者返回一个点?对于CalculatePoint,返回null表示失败。这意味着必须强制转换回不可为null的类型,这似乎太过分了。

另一种方法是返回布尔boSuccess,将结果(Point或List)作为"out"参数,并将其称为TryToCalculatePoint或其他。。。

什么是最佳实践?

编辑:我不想使用异常进行流量控制!失败有时是意料之中的事。

如何指示方法不成功

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

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

我不喜欢将exception用于"正常"行为(如果您希望函数对某些条目无效)。

为什么会失败?如果是因为调用方所做的事情(即提供的参数),那么抛出ArgumentException是完全合适的。Try[…]方法可以避免异常。

不过,我认为提供抛出异常的版本是个好主意,这样,那些希望自己总是提供良好数据的呼叫者,如果他们错了,就会收到一条适当的强消息(即异常)。

另一种选择是抛出异常。然而,您通常只想在"异常情况"中抛出异常。

如果失败案例是常见的(而不是特殊的),那么您已经列出了您的两个选项编辑:您的项目中可能有一个约定,即如何处理此类非特殊情况(无论是返回成功还是返回对象)。如果没有现有的约定,那么我同意lucasbfr的观点,并建议您返回成功(这与TryParse(…)的设计方式一致)。

如果故障是由于特定原因造成的,那么我认为可以返回null或bool并有一个out参数。然而,如果无论失败如何,你都返回null,那么我不建议这样做。异常提供了一组丰富的信息,包括失败的原因,如果你得到的都是null,那么你怎么知道这是因为数据错误、内存不足还是其他一些奇怪的行为。

即使在.net中,TryParse也有一个Parse兄弟,所以如果你想的话,你可以得到异常。

如果我提供了一个TrySomething方法,我也会提供一个在失败时抛出异常的Something方法。然后由打电话的人决定。

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

您的原始代码:
public Point CalculatePoint(…out Boolean boSuccess)
public List CalculateListOfPoints(…out Boolean boSuccess);

会变成public bool CalculatePoint(…out(或ref)Point CalculatedValue)
public bool CalculateListOfPoints(…out(或ref)List CalculatedValues);

基本上,你把成功/失败作为回报。

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

  1. 当返回类型是值类型时,如Point,使用C#的Nullable特性并返回Point?(又名Nullable),这样你仍然可以在失败时返回null
  2. 出现故障时抛出异常。关于什么是"异常"和什么不是"异常"的整个争论/讨论是一个没有争议的问题,这是你的API,你决定什么是异常行为
  3. 采用类似于Microsoft在Int32等基类型中实现的模型,提供CalculatePoint和TryCalculatePoint(Int32.Parse和Int32.TryParse),并有一个throw和一个return bool
  4. 从方法中返回一个具有两个属性的泛型结构,即bool Success和GenericType Value

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

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

如果失败是常见的和非关键的,那么让您的方法返回一个指示其成功的布尔值,并使用out参数来传达结果。在散列中查找密钥,在没有可用数据的情况下尝试读取非阻塞套接字上的数据,所有这些示例都属于这一类。

如果失败是意外的,则直接返回结果,并通过异常传递错误。以只读方式打开文件、连接到TCP服务器都是不错的选择。

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

ReturnPoint.Empty。当您想要检查结构创建是否成功时,返回一个特殊字段是一种.NET设计模式。尽可能避免使用out参数。

public static readonly Point Empty

我正在试验的一种模式是返回一个可能。它具有TryParse模式的语义,但与错误时返回null模式的签名相似。

无论如何,我还不相信,但我提出这一点供你们集体考虑。它的好处是不需要在方法调用之前定义变量,以便在方法的调用位置保存out参数。它也可以用ErrorsMessages集合进行扩展,以指示失败的原因。

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

我认为最佳实践是返回值意味着成功,异常意味着失败。

在您提供的示例中,我看不出有什么理由不应该在发生故障时使用异常。

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

// 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;
}

两全其美!

bool TrySomething()至少是一种实践,它适用于.net的解析方法,但我认为我总体上不喜欢它。

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

在大多数情况下,当您不希望出现异常时,尽可能返回null是可以的。

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

您不希望在预期发生的情况下抛出异常,正如@Kevin所说的异常是针对异常情况的。

你应该返回一些预期的"失败",通常null是我选择的错误返回。

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

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

有了Point,您可以发回Point.Empty作为失败时的返回值。现在,所有这些实际上都是为X和Y值返回一个0的点,所以如果这是一个有效的返回值,我会远离它,但如果你的方法永远不会返回(0,0)点,那么你可以使用它。

对不起,我刚刚记住了Nullable类型,你应该看看。不过,我不太确定开销是多少。