以下是我所拥有的设置的简化示例。我的问题是一个异常被抛到一个低水平,然后会冒出来。但是,更高级别的类不知道在使用较低级别的类函数时会有什么恐怖等待它们。我的意思是开发人员会使用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();
}
}
为了澄清一些似乎在评论中产生的混淆,我将提出我目前正在考虑的两个解决方案:
答案 0 :(得分:1)
.NET和Java中异常处理的一个主要限制是,没有标准化的方法可以通过这种方法区分由于方法所期望的原因从方法抛出的某种类型的异常,而不是异常。由于外部方法没有预料到的原因,嵌套方法抛出的相同类型。如果方法的目的是调用一些用户提供的委托,我知道的唯一方法是可靠地区分被调用委托抛出的异常和调用它的过程中发生的异常要么传递方法,要么它将包含在它直接抛出的任何异常中的标识令牌,或者将该方法作为在调用用户提供的回调时发生的策略包装异常的问题。这两种方法都不是很优雅。
因为没有标准化的方法可以识别异常,这些异常表明操作“干净地”没有副作用,从那些表明存在更严重问题的异常,我建议代码不应该依赖于“严重”防止“传染性”数据损坏的例外情况。相反,任何时候异常都可能导致对象处于损坏状态,该对象应该显式无效,以防止从其中读取损坏的数据并将其复制到其他地方(可能会覆盖会有的内容)是唯一的好副本)。在不需要损坏的对象并且堆栈展开会导致它失效的情况下,没有问题。在无效的对象被证明对系统操作至关重要的情况下,程序应该被强制关闭,并且使对象无效将使得这种情况比抛出“严重”异常更可靠。
不幸的是,C#和VB.NET都没有提供一种非常好的模式来保护这种方式的对象。 VB.NET比C#具有更好的异常处理能力,并且可以实现正确的模式(基于抛出的异常在finally
块中执行操作,但没有捕获异常),尽管很不方便,但是语言。在C#中,找出try
块内发生异常的唯一方法是捕获并重新抛出一个具有一些副作用的动作。
答案 1 :(得分:0)
对Anders Hejlsberg进行了一次精彩的采访,名为The Trouble with Checked Exceptions。 (Anders领导了设计C#编程语言的团队。)
您正陷入异常聚合陷阱。您可能不应该问“下级系统可能会抛出哪些异常?”在许多情况下,答案是包含数百个独特例外的列表。
相反,你应该问自己“我怎样才能向开发者提供有用的信息?”您应该记录代码明确抛出的异常,或者在极少数情况下记录很可能发生的相关异常以及调用者可能特别感兴趣的异常。调用代码的开发人员可以确定处理这些错误的必要性或将这些信息传递给他们代码的调用者 - 或者根本不对其进行任何操作。毕竟,异常是例外,并且在某个级别上,抛出哪个数据库错误并不重要 - 响应中采取的步骤是相同的(例如,如果可能的话,稳定环境,写入错误日志并终止执行)。