无论如何,我对于何时传播异常,何时包装异常以及区别感到有些困惑。

目前,我的理解告诉我包装异常将涉及采用像DriveNotFound这样的异常(在IO中),然后将其与常规IOException包装在一起。

但是,通过传播异常的概念,只有当我有一个空的catch子句时,这只会发生吗?因此,在ASP.NET Web应用程序中,它将传播到global.asax。或者,对于最近部署的Web应用程序,未处理的HTTPException导致黄屏死亡,并向Windows Server(这是我正在重写的Web应用程序)写入日志。因此,该异常发生在方法中,可以在类级别处理该异常,将其显示在页面中,然后转到global.asax或Windows Server。

为什么我要用一个更通用的异常来包装异常?规则是处理最特定类型的异常(因此显然找不到驱动器,因此使用DriveNotFound)。另外,在包装和替换异常之间如何选择?

异常处理链仅仅是try和catch(或catchs)子句吗?我想从措辞上是可以的。

最后,为什么以及如何让异常在调用堆栈中传播?

我确实阅读了有关异常处理的MS PandP指南,但我想这些示例还不足以让我完全理解所有内容。

这个问题来自企业库包装/传播异常等的能力。这是我不确定的传播方式,以及替换/包装异常的区别。

另外,可以在catch块中插入复杂的错误处理逻辑(例如ifs/elses之类的东西)。

谢谢

最佳答案

不少于6个问题:-)



异常将向上传播,直到被处理该特定异常类型或更接近该异常层次结构基本类型的异常类型的调用堆栈进一步捕获为止。因此,例如,所有托管异常都源自System.Exception,因此拦截System.Exception的catch块将捕获每个托管异常。



我不确定您所说的“换行”是什么意思。您是说捕获一个异常,将其替换为另一个,然后将原始添加为新异常的InnerException属性吗?或者是其他东西?

我认为几乎没有充分的理由将异常替换为更通用的异常。但是,出于以下三个原因中的一个或多个,您当然可以用另一个异常替换一个异常:

  • 对调用者隐藏实现细节。
  • 改善抽象级别,以使其对调用者更有意义。
  • 抛出一个非常特殊的自定义异常。



  • 对不起,但是我仍然不明白您如何将这两个定义为不同。



    以下是引发异常时发生的情况的基本信息:
  • CLR顺序在本地Try ... End Try块内的Catch块列表中向下移动,以查找具有匹配抛出的异常的异常过滤器的本地Catch块。
  • 如果本地Catch块具有与所引发的确切异常匹配的异常过滤器,则将执行该Catch块中的代码,然后执行Final模块中的代码。然后,在End Try之后的第一条语句处继续执行。
  • 或者,如果引发的异常是由本地Catch块指定的异常派生的,则发生与第二步中所述相同的操作。例如,捕获ArgumentException的异常过滤器还将捕获从ArgumentException派生的异常,例如ArgumentNullException,InvalidEnumArgumentException,DuplicateWaitObjectException和ArgumentOutOfRangeException。
  • 如果没有本地Catch块与引发的异常匹配,则CLR逐个方法返回调用堆栈,以查找要响应该异常的Catch块。如果在调用堆栈中找不到匹配的Catch块,则认为该异常未处理。
  • 或者,如果在调用堆栈中的某个位置找到匹配的Catch块,则将执行throw和catch之间的每个Final块中的代码。这始于引发异常的Try块的Final,并在捕获异常的方法下面的Final中结束。
  • 对捕获异常的以下所有方法完成此清理后,控制权转移到捕获异常的Catch块,并执行此代码。接下来运行的是Try的Final块,在该块中捕获了异常。现在,调用栈已经解开并且错误清理已经完成,最后一步是在End Try之后捕获到异常的第一条语句处继续执行。
  • 如果Catch块中的代码导致引发另一个异常,则使用InnerException属性将原始异常自动附加到新异常。这样,可以在不丢失任何信息的情况下堆叠异常。
  • 您应该避免将清理代码放在可能引发异常的Final块中,除非该代码在其自己的Try块中。如果没有此附加保护,CLR的行为就像在Final模块之后的末尾抛出新异常,并在调用堆栈中查找要响应新异常的远程Catch块。除非原始的Catch块将其保存,否则原始的异常将丢失。



  • 原因:每当您不特别了解异常并知道如何从异常中恢复时,都应使其向上传播。

    方法:仅捕获您理解并知道如何处理的异常类型。有时,您需要任何异常的详细信息才能进行适当的恢复。在这种情况下,您可以捕获它,进行恢复,然后使用 throw重新抛出它; 语句。



    通常是,因为由Catch块中的代码引起的任何新异常都将通过InnerException属性自动将旧异常附加到该异常。但是,如果可以避免的话,激发这种机制是不明智的,因此拥有的代码越简单越好。使Catch代码保持简单的另一个很好的理由是,它通常不会经过与主代码相同程度的测试。

    10-08 13:36
    查看更多