天天看点

C#:在catch中return,会执行finally吗?

来自博客

<a href="http://blog.csdn.net/vipxiaotian/article/details/1524059" target="_blank">http://blog.csdn.net/vipxiaotian/article/details/1524059</a>

请参考下面一段简单的语句块:

1: try

2: {

3: throw new Exception("new exception");

4: }

5: catch(Exception ex)

6: {

7: return;

8: }

9: finally

10: {

11: Console.WriteLine("a");

12: }

       大家有没有想过执行到第七步之后会出现什么结果?line7是一条return语句,按道理来说return语句的作用就是跳出当前函数并继续调用地址的下一条语句,那么说就不执行finally,但是我想大家应该都记得finally的作用:确保有无异常的情况下finally块中的语句都能执行……于是,矛盾就这样产生鸟。。。

      在继续下去看答案之前,亲爱的读者们,你们觉得会是什么结果呢?finally会不会执行呢?请先思考一下再看答案。

       既然在程序层看不出猫腻,那么我们不妨深入IL层去挖掘一下,上面代码的IL是这样子地:

  .try

  {

    .try

    {

      IL_0000:  ldstr      "new exception"

      IL_0005:  newobj     instance void [mscorlib]System.Exception::.ctor(string)

      IL_000a:  throw

    }  // end .try

    catch [mscorlib]System.Exception 

      IL_000b:  stloc.0

      IL_000c:  leave.s    IL_0019

    }  // end handler

  }  // end .try

  finally

    IL_000e:  ldstr      "a"

    IL_0013:  call       void [mscorlib]System.Console::WriteLine(string)

    IL_0018:  endfinally

  }  // end handler

  IL_0019:  ret

      请注意上面上面黄色部分代码,在catch块中,使用了leave.s这条命令来跳转到IL_0019这一行,而0019这一行正是ret命令,看起来……应该不会执行到finally才对~~难道说,从catch块就直接跳出了?!

      我想该是时候去弄明白leave.s这条命令的作用了,看看Microsoft给出的定义:

格式

汇编格式

说明

DE int8 &gt;

leave.s target

退出受保护的代码区域(短格式)。

没有为此指令指定任何堆栈转换行为。

leave.s 指令无条件将控制转移到传递的目标指令,这表示为距当前指令之后的指令的开始处的 1 字节有符号偏移量。

leave.s 指令类似于 br 指令,但它可用于退出 try、filter 或 catch 块,而一般分支指令只能在此类块中使用以在其内部转移控制。leave.s 指令清空计算堆栈并确保执行周围适当的 finally 块。

不能使用 leave.s 指令退出 finally 块。为了简化异常处理程序的代码生成,一个有效的方法是在 Catch 块的内部使用 leave.s 指令将控制转移到关联的 try 块中的任何指令。

如果指令有一个或多个前缀代码,则只能将控制转移到其中的第一个前缀。

      OK,至此,一切明了了<b>~~leave.s会确保finally块的执行,所以,即使在catch中使用了return语句想直接跳出,还是会先执行finally再return的</b>