1

下面是我所拥有的设置的简化示例。我的问题是在低级别引发异常,然后会冒泡。但是,较高级别的类不知道当他们使用较低级别的类函数时会发生什么恐怖事件。我的意思是,开发人员会出现并使用 Class3.DoWork3(),而不需要对可怕的“MyCustomException”进行任何异常处理。

我接近这一切都错了吗?我不想多次捕获并抛出相同的异常(例如,我不需要在 Class2 中进行任何类型的清理)。

public class Class1
{
    <exception cref="MyCustomException">description</exception>
    public void DoWork1()
    {
        throw new MyCustomException("I have failed you class1.");
    }
}

public class Class2
{
    public void DoWork2()
    {
        var classOne = new Class1();

        // Here I can see that DoWork1() will throw a 'MyCustomException'
        classOne.DoWork1();
    }
}

public class Class3
{
    public void DoWork3()
    {
        var classTwo = new Class2();

        // I can no longer see that Class2.DoWork2() will throw a 'MyCustomException'
        classTwo.DoWork2();
    }
}

为了消除评论中似乎产生的一些混淆,我将提出我目前正在考虑的两种解决方案:

  1. 使用与 Class1 相同的 MyCustomException 注释标记 DoWork2
  2. 在 DoWork2 中抛出一个不同的异常并用这个新异常标记它。这个选项似乎是最强大的,因为它允许更详细的日志(例如,代码在其执行路径中的确切位置)。对于简单化的场景,这种方式似乎有点过头了,这就是为什么我想知道(1)是否是这个问题的可接受解决方案?
4

2 回答 2

1

.NET 和 Java 中异常处理的主要限制之一是,没有标准化的方法可以让代码区分由于方法所期望的原因而从方法中抛出的某种类型的异常,与该方法所期望的相同类型的异常。被嵌套方法抛出,原因是外部方法没有预料到。如果方法的目的是调用某个用户提供的委托,那么我所知道的唯一可靠区分被调用委托抛出的异常和在调用它的过程中发生的异常的方法是向该方法传递一个身份令牌,它将包含在它直接抛出的任何异常中,或者将方法作为在调用用户提供的回调时发生的策略包装异常的问题。这两种方法都不是非常优雅。

因为没有标准化的方法来识别表明操作“完全”失败而没有副作用的异常,从那些表明存在更严重问题的异常中,我建议代码不应该依赖“严重”异常来防止“传染性”数据损坏。相反,任何时候异常可能导致对象处于损坏状态,都应该明确地使对象无效,以防止从中读取损坏的数据并将其复制到其他地方(可能会覆盖本应是唯一好的副本)。在不需要损坏的对象并且堆栈展开会导致它失效的情况下,没有问题。在被失效的对象被证明对系统操作至关重要的情况下,程序应该被强制关闭,并且使对象失效将比抛出“严重”异常更可靠地发生这种情况。

不幸的是,C# 和 VB.NET 都没有提供非常好的以这种方式保护对象的模式。VB.NET 比 C# 具有更好的异常处理能力,并且finally可以在该语言中实现正确的模式(根据抛出的异常在块中执行操作,但不捕获异常),尽管很笨拙。在 C# 中,找出try块中发生的异常的唯一方法是捕获并重新抛出,这是一个有一些副作用的操作。

于 2013-10-01T15:14:40.783 回答
0

Anders Hejlsberg 有一篇精彩的采访,题为The Trouble with Checked Exceptions。(Anders 领导了设计 C# 编程语言的团队。)

您陷入了异常聚合陷阱。您可能不应该问“较低级别的系统可能会抛出哪些异常?” 在许多情况下,答案将是一个包含数百个独特例外的列表。

相反,您应该问自己“我如何向开发人员提供有用的信息?” 您应该记录您的代码明确抛出的异常,或者在极少数情况下,记录很可能发生并且调用者可能特别感兴趣的相关异常。调用您的代码的开发人员可以确定处理这些错误的必要性或将这些信息传递给他们代码的调用者——或者干脆什么都不做。毕竟,异常是异常的,并且在某个级别上,抛出哪个数据库错误并不重要 - 响应所采取的步骤是相同的​​(例如,如果可能的话稳定环境,写入错误日志并终止执行)。

于 2013-12-17T05:45:35.760 回答