catch关键字如何确定抛出的异常类型?

Ian*_*ien 1 .net c# exception try-catch

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) { }
Run Code Online (Sandbox Code Playgroud)

通过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
Run Code Online (Sandbox Code Playgroud)

但是catch,为了确定抛出的异常类型,关键字的作用仍然不明确.

Han*_*ant 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关键字的程序员之外,这与它的实现方式没有任何关系.