catch
关键字如何确定抛出的异常类型?选择执行哪个catch块会发生什么过程?
try
{
int[] myArray = new int[0];
myArray[1] = 0;
}
catch (IndexOutOfRangeException ex) { } // how does the CLR know to enter here?
catch (InvalidCastException ex) { }
通过ILdasm
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 28 (0x1c)
.maxstack 3
.locals init (int32[] V_0,
class [mscorlib]System.IndexOutOfRangeException V_1,
class [mscorlib]System.InvalidCastException V_2)
IL_0000: nop
.try
{
IL_0001: nop
IL_0002: ldc.i4.0
IL_0003: newarr [mscorlib]System.Int32
IL_0008: stloc.0
IL_0009: ldloc.0
IL_000a: ldc.i4.1
IL_000b: ldc.i4.0
IL_000c: stelem.i4
IL_000d: nop
IL_000e: leave.s IL_001a
} // end .try
catch [mscorlib]System.IndexOutOfRangeException
{
IL_0010: stloc.1
IL_0011: nop
IL_0012: nop
IL_0013: leave.s IL_001a
} // end handler
catch [mscorlib]System.InvalidCastException
{
IL_0015: stloc.2
IL_0016: nop
IL_0017: nop
IL_0018: leave.s IL_001a
} // end handler
IL_001a: nop
IL_001b: ret
} // end of method Program::Main
但是仍然不清楚catch
关键字为了确定抛出的异常类型所做的事情。
答案 0 :(得分:12)
只是简短的回答,真正的答案需要一本书。 .NET中的异常处理非常复杂,涉及许多移动部件。包括Windows中异常的本机支持(SEH,结构化异常处理),CLR中最大和最复杂的代码块之一(例外代码,代码为232KB),程序集中的元数据(这就是为什么你要这样做)看到它带有任何IL地址)和抖动。
throw 关键字引发异常,它在运行时触发RaiseException()Windows api函数。 Windows通过运行由RtlAddFunctionTable()注册的异常过滤器来寻找愿意处理异常的代码。这些是在CLR中实现的。它反过来使用由抖动生成的元数据,当抖动将IL转换为机器代码时,在即时编译时构建的数据表。抖动使用通过.try和catch等指令添加到程序集元数据的元数据信息,您在反汇编中看到的内容。表数据包含有关特定异常类型的catch子句的代码范围的信息。允许CLR选择应该恢复执行的位置,并告诉Windows继续处理异常。
了解它的起源并知道停止的位置,Windows现在开始展开堆栈帧,并在必要时调用finally块。接下来,它在catch块的第一个机器代码指令处设置指令指针。
除此之外还有很多令人讨厌的小细节。就像ThreadAbortException的语义,vb.net Catch When关键字,finally块的复杂化引发异常,当SEH纯粹基于堆栈帧时处理try块作用域,当线程需要中止时不可捕获异常的概念。拿书的东西,但没有人会写一个,因为读者会立即入睡。
.NET中的异常处理是一个充满了铅的冰山。 99%是在水中,这是CLR中 最成功的抽象之一。除了经常使用catch关键字的程序员之外,这与它的实现方式没有任何关系。
答案 1 :(得分:2)
免责声明:我没有读过CLR规范,我知道异常远比“普通”代码复杂得多。但是,这是一种非常简单的方法,我相信它会起作用。
IndexOutOfBounds
或HttpException
而非基础Exception
try
块内捕获异常时,运行时将有一个预期类型的异常列表(即每个catch
块一个)。假设它是List<Type> TheseExceptionsMayOccur
foreach(Type ExceptionType in TheseExceptionMayOccur)
{
if(e is ExceptionType )
//run the respective catch block
}