hf

导航

 

问题:try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

答案是会在return前执行。不过这个很容易造成误解,例如下边的代码:

static int Fun() {
    var i = 0;
    try {
        return ++i;
    }
    finally {
        ++i;
    }
}

按照finally会在return前执行,您也许会期望返回值为2,实际上返回的是1。看下il:

.method private hidebysig static int32  Fun1() cil managed
{
  // Code size       22 (0x16)
  .maxstack  2
  .locals init ([0] int32 i,
           [1] int32 CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.0
  .try
  {
    IL_0003:  nop
    IL_0004:  ldloc.0
    IL_0005:  ldc.i4.1
    IL_0006:  add
    IL_0007:  dup
    IL_0008:  stloc.0
    IL_0009:  stloc.1
    IL_000a:  leave.s    IL_0013
  }  // end .try
  finally
  {
    IL_000c:  nop
    IL_000d:  ldloc.0
    IL_000e:  ldc.i4.1
    IL_000f:  add
    IL_0010:  stloc.0
    IL_0011:  nop
    IL_0012:  endfinally
  }  // end handler
  IL_0013:  nop
  IL_0014:  ldloc.1
  IL_0015:  ret
} // end of method Program::Fun1

简单的说,在return(C#)前会用leave.s指令跳到finally块执行,然后才真正返回(ret)。要注意的是在return前同时会把要返回的值保存在locals[1]中,而在finally块修改的是locals[0],最后返回的也是locals[1],所以finally不会修改到返回值,返回的依然是1。

实际上编译器总是会为返回值生成一个变量,我猜的,还不知道为什么。。。希望能有高人指点下。

例如这样的代码:

 static Int32 Fun2() {
     return 0;
 }

会生成il:

.method private hidebysig static int32 
        Fun2() cil managed
{
  // Code size       7 (0x7)
  .maxstack  1
  .locals init ([0] int32 CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.0
  IL_0003:  br.s       IL_0005
  IL_0005:  ldloc.0
  IL_0006:  ret
} // end of method Program::Fun2
posted on 2010-07-15 18:36  hf  阅读(424)  评论(0)    收藏  举报