如何在库实现中冒泡/处理C#异常

时间:2012-06-13 07:24:58

标签: c# .net exception

从库中冒出异常的最佳方法是什么?当我实现一个接口时,使用与我的实现细节有关的异常来阻止主叫方是一个好的或坏的做法?我有以下实现,其中每个实现错误都隐藏在远离主叫方的位置。它看起来是实现关注点分离的最简洁方式。但我到处都读到你需要触及未触及的异常。

public class OneException : Exception
{
    public OneException()
    {
    }

    public OneException(string message): base(message)
    {
    }

    public OneException(string message, Exception innerException)
      : base(message, innerException)
    {
    }
}

我的图书馆实施:

public class MyLib : IMyLib
{
    public int Divide(int a, int b)
    {
        try
        {
            if (b == 1) throw new OneException();
            return a / b;
        }
        catch (OneException e)
        {
            throw new ApplicationException("Please do not divide by 1", e);
        }
        catch (Exception e) // divide by zero and others
        {
            throw new ApplicationException("Oops", e);
        }
    }
}

7 个答案:

答案 0 :(得分:2)

为异常冒泡选择正确的策略取决于两个主要因素:

  1. 您是否希望尽可能多地向调用者提供有关异常上下文的详细信息?
  2. 您是否要隐藏来自来电者的敏感异常数据?
  3. 如果要提供有关异常上下文的更多详细信息,将异常包装到某个更具体的异常中是一个很好的策略。这里最明显的例子是业务例外

    如果要隐藏敏感数据,可以考虑替换异常。当呼叫方不受信任时,这种方法通常用于服务中。

    注意:除非它不是正常程序流程的一部分,否则不应该“吞下”异常。

答案 1 :(得分:1)

作为一般规则,只处理你可以处理的那些例外。

在您的库实现中,您会捕获不同的异常OneExceptionException,并将其重新抛出为ApplicationException。我认为这是一种不好的做法,因为你完全隐藏原始错误的含义。

使用您的库Divide()方法的客户端代码应该知道究竟发生了什么,如果冒泡的唯一例外是通用ApplicationException,那么没有线索关于原因?< / p>

您在此处执行的操作是抛出异常,在同一方法中捕获它并重新抛出不同的异常。

让异常冒泡到客户端代码,以便客户端可以自行决定如何处理它 - 或者,如果有的话

答案 2 :(得分:1)

这取决于。如果由于某些业务规则而要处理异常并引发自定义异常,则确保处理异常并记录它或引发新的自定义异常,例如在示例代码中,为{{1}引发异常}。

另一个例子可能是,如果要在表中输入数据并获得主键约束异常,则可以根据库规范捕获异常并引发自己的自定义异常,也可以将异常保留为是,在调用代码中处理。

如果要维护内部错误/异常日志,则在库中处理异常可能会有所帮助。您可以记录异常,然后将其抛出,以便它可以冒泡到调用代码。 但恕我直言,如果您既没有记录或提出自定义异常,最好不要触摸异常,以便可以在调用代码中处理

答案 3 :(得分:1)

尝试记录异常,这始终是一个好习惯。通过这种方式,客户端实际上会知道出了什么问题。

答案 4 :(得分:1)

问自己这些问题:

  • 作为开发人员,您希望消费者(来电者)了解您的图书馆?

  • 作为消费者,如果发生错误,您会想要什么?

如果标准的.Net版本不足以达到此目的,您应该只开始宣传自己的例外类型。一个例子是COM相关的错误 - 您可能希望为特定的错误条件创建自定义异常,以避免抛出嵌入了特殊数字的COMExceptions。

我会说你的例子中的OneException是浪费时间 - 为什么抛出,捕获然后换行并重新抛出作为标准异常?为什么不先抛出一个ApplicationException?这与使用异常来控制程序流接近,这是一种反模式。

答案 5 :(得分:1)

系统涵盖这两种例外情况。对于b = 1的情况,使用ArgumentOurOfRange异常,对于b = 0的情况,使用DivideByZeroException。因此,对于非常简单的示例库,不需要创建其他异常(这不是一个好习惯)。立即抛出异常是一个要求问题。在大多数情况下(良好实践),您可以使用try / catch(/ finally)抛出调用者可以处理的异常。

答案 6 :(得分:1)

Single Responsibility Principle保持一致,你应该照顾你的图书馆应该做的事情(如果可能的话)。否则,您应该让呼叫者处理它。

在您的示例中,您正确地抛出了一个被零除的异常。处理此问题不是您图书馆的责任(除非您将其宣传为“安全”划分方法)。该错误是由不正确的客户端输入引起的,因此它应该是处理它的客户端。

然而,你的OneException将是一个不寻常的例外。为什么客户不能除以一个?它当然不会造成伤害。这可能是一个人为的例子,但除非确实存在无法在内部解决的问题,否则不应抛出异常。如果有人想要除以1,为什么不允许他们这样做呢?

良好的异常处理将通知客户输入和/或系统故障的问题,而不是逻辑中的错误。