最后了解try catch的MSIL

Pan*_*kaj 9 c# il cil

我有以下代码

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

上面代码生成的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
Run Code Online (Sandbox Code Playgroud)

我有以下问题:

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

Jon*_*eet 11

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

在这一点上不确定.它可能只是ildasm选择反编译的方式.ECMA-335表示SEHClause在a之后如何指定元素有限制TryBlock,但我还没有找到这些限制.

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

不,那是跳跃finally块-返回值,有效.你有很多返回语句都返回相同的东西,以及无法访问的代码,这没有帮助,但我相信这一点基本上只是移动到ret外面的trycatch.我认为编译器正在为返回值有效地设置一个额外的局部变量.

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

这就是C#和IL的定义方式 - 无论你退出finally块,都会执行块.