最后了解try catch的MSIL

时间:2014-12-22 11:24:46

标签: c# cil il

我有以下代码

    using System;

class Pankaj
{
    public static int Main()
    {
        int returnValue=0;
        try
        {
            return returnValue;
            throw new Exception();

        }
        catch(Exception ex){
            return returnValue;
        }
        finally
        {
            returnValue++;
        }
        return returnValue;
    }
}

上述代码生成的MSIL是:

.method public hidebysig static int32  Main() cil managed
{
  .entrypoint
  // Code size       18 (0x12)
  .maxstack  2
  .locals init (int32 V_0,
           int32 V_1)
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  .try
  {
    .try
    {
      IL_0002:  ldloc.0
      IL_0003:  stloc.1
      IL_0004:  leave.s    IL_0010
    }  // end .try
    catch [mscorlib]System.Exception 
    {
      IL_0006:  pop
      IL_0007:  ldloc.0
      IL_0008:  stloc.1
      IL_0009:  leave.s    IL_0010
    }  // end handler
  }  // end .try
  finally
  {
    IL_000b:  ldloc.0
    IL_000c:  ldc.i4.1
    IL_000d:  add
    IL_000e:  stloc.0
    IL_000f:  endfinally
  }  // end handler
  IL_0010:  ldloc.1
  IL_0011:  ret
} // end of method Pankaj::Main

我有以下问题:

  1. 为什么try catch再次包含在try块中。
  2. 看起来像leave.sp和catch块的最后一行最后指向IL_0010 但是在IL_0010行它的ldloc.1,我认为这意味着在堆栈上加载局部变量1,然后它指向finally块。 是不是像位置1那样我们有最后一个块的地址。
  3. 如果我从catch块中抛出或返回一些内容,那么调用语句如何落到finally块中,它已经从catch块返回,但仍然会执行finally块。

2 个答案:

答案 0 :(得分:10)

  

为什么try catch再次包含在try块中。

对此不确定。它可能只是ildasm选择反编译它的方式。 ECMA-335表示SEHClause之后TryBlock元素的指定方式存在限制,但我还没有找到这些限制。

  

看起来像leave.sill和catch块的最后一行是指向最后即IL_0010但是在行IL_0010它的ldloc.1我认为这意味着在堆栈上加载局部变量1,然后它如何指向finally块。它是在位置1,我们有finally块的地址。

不,在<{em} finally块之后跳转到 - 有效地返回值。你没有得到很多的返回语句并且返回相同的东西以及无法访问的代码并没有帮助,但我相信这一点基本上只是为了移动{{ 1}}在rettry之外。我认为编译器正在为返回值有效地设置一个额外的局部变量。

  

如果我从catch块中抛出或返回一些内容,那么调用语句如何落入finally块,它已经从catch块返回,但仍然会执行finally块。

如何定义C#和IL - catch块将被执行但是你退出块。

答案 1 :(得分:2)

Jon Skeet已经回答了最后两个问题,所以我只关注第一个问题。

  

为什么try catch再次包含在try块中。

这有几个原因:

  • 将catch处理程序放在与finally处理程序关联的try块中意味着即使在catch块中抛出异常也会发生finally(我认为这是C#规范所要求的 - 尽管我并不是这样)直接引用它所说的内容。)
  • CLI规范对重叠的异常处理区域有一些严格的规则,这些规则排除了catch和finally块保护相同的代码而不使finally块也保护catch块或catch块也保护finally块(规范以比此更一般的术语讨论它,您可以在ECMA-335的第1分区第12.4.2.7节中找到详细信息。)