请解释 CLR 如何实现异常处理,具体包括异常抛出后运行时环境如何查找匹配的处理器,以及 finally 块在其中的执行时序。
考察说明
考察对 CLR 异常处理底层机制的理解,包括异常对象创建、栈展开和 finally 执行顺序。
回答思路
- 【回答框架 1】CLR 的异常处理基于结构化异常处理(SEH),每个方法都包含异常处理信息,存储在方法的 EH 表中。当异常抛出时,CLR 会定位当前方法的 EH 表,检查是否有匹配的 catch 块,若没有则向外层调用栈继续查找。
- 【回答框架 2】抛出异常时,CLR 会创建异常对象,记录调用栈信息。在查找处理器的过程中,会执行 finally 块,确保资源得到清理。找到匹配的 catch 后,执行 catch 块,然后执行 finally 块,再继续执行后续代码。
- 【回答框架 3】在 .NET 中,异常处理遵循最近优先原则,即从当前方法开始向外层查找,先匹配类型最具体的异常处理器。finally 块在异常传播路径上保证执行,无论是否有异常发生。
- 【回答框架 4】对于性能来说,抛出异常的成本较高,因为需要创建异常对象、捕获调用栈和执行栈展开。因此,在代码中应避免使用异常作为控制流语句。
- 【关键点 1】CLR 使用 EH 表记录异常处理器信息,异常处理基于 SEH。
- 【关键点 2】异常抛出时,先查找匹配的 catch,执行相关 finally 后,再继续执行。
- 【关键点 3】finally 块在异常传播和正常退出时都会执行。
- 【关键点 4】异常处理遵循最近优先和类型匹配原则。
- 【易错点 1】误以为 catch 块内抛出异常不会执行 finally,实际上 finally 始终执行。
- 【易错点 2】在性能敏感路径过度使用异常会导致明显开销。
- 【易错点 3】忽略异常处理器的匹配顺序,可能导致捕获不到预期的异常类型。