不少于6个问题 :-)
但是关于传播异常的概念,这只会在有空catch子句的情况下发生吗?
异常将向上传播,直到被更高层次的调用堆栈中处理该特定异常类型或更接近该异常层次结构基类型的异常类型的catch块捕获。例如,所有托管异常都从System.Exception派生,因此拦截System.Exception的catch块将捕获每个托管异常。
为什么我要用更通用的异常来包装异常?
我不确定你指的是什么。您是否意味着捕获异常,用另一个替换它,并将原始异常添加为新异常的InnerException属性?还是其他事情?
我认为很少有很好的理由使用更通用的异常来替换异常。但是,您可以确实将异常替换为另一个异常,出于以下三个原因之一或多个原因:
- 隐藏对调用者的实现细节。
- 提高抽象级别,使其对调用者更有意义。
- 抛出与处理的问题非常相关的自定义异常。
此外,我如何在包装和替换异常之间进行选择?
对不起,但我仍然不理解您如何将这两者定义为不同的事情。
异常处理链只是try和catch(或catches)子句吗?
以下是抛出异常时发生的基本情况:
如果本地Catch块具有与抛出的精确异常匹配的异常过滤器,则该Catch块中的代码将被执行,然后执行Finally块中的代码。然后继续执行End Try后的第一条语句。
或者,如果抛出的异常派生自本地Catch块指定的异常,则会发生与第二步描述的相同的操作。例如,捕获ArgumentException的异常过滤器也会捕获派生自ArgumentException的异常,例如ArgumentNullException、InvalidEnumArgumentException、DuplicateWaitObjectException和ArgumentOutOfRangeException。
如果没有本地Catch块与抛出的异常匹配,则CLR沿调用堆栈向上走,逐个查找要响应异常的Catch块。如果在调用堆栈中找不到匹配的Catch块,则认为该异常未处理。
或者,如果在调用堆栈中的某个位置找到了匹配的Catch块,则将执行throw和catch之间的每个Finally块中的代码。这始于抛出异常所在的Try块的Finally,并在捕获异常的方法下面的方法的Finally结束。
在完成所有捕获异常下面的方法的清理之后,控制转移到捕获异常的Catch块,并执行此代码。接下来运行的是捕获异常的Try的Finally块。现在,由于调用堆栈已被展开并完成了错误清理,因此最后一步是继续执行捕获异常的End Try后的第一条语句。
如果Catch块中的代码导致抛出另一个异常,则使用InnerException属性将原始异常自动附加到新异常上。通过这种方式,异常可以堆叠而不会丢失任何信息。
您应避免将可能引发异常的清理代码放置在Finally块中,除非该代码位于其自己的Try块内。如果没有添加此额外的保护,则CLR会表现得好像新异常是在Finally块结束后抛出的,并查找远程Catch块以响应新异常。除非原始Catch块保存它,否则原始异常将丢失。
最后,我为什么要让异常向调用栈上传播?
为什么:当你不明确了解异常并知道如何从中恢复时,应该让它向上传播。
如何:只捕获你理解并知道如何处理的异常类型。偶尔需要异常的详细信息才能进行适当的恢复。在这种情况下,您可以捕获它,执行恢复操作,然后使用throw;语句重新抛出它。
此外,将复杂的错误处理逻辑插入catch块中是否可行(例如if/else之类的)。
一般来说,可以,因为你的Catch块中的代码引发的任何新异常都会自动通过InnerException属性附加到旧异常上。但是,如果有可能避免触发此机制,最好不要挑衅它,所以你的代码越简单,越好。保持Catch代码简单的另一个很好的原因是,通常它不会经过与主线代码相同的测试程度。