KiMoGiGi 技术文集

不在乎选择什么,而在乎坚持多久……

IT博客 首页 联系 聚合 管理
  185 Posts :: 14 Stories :: 48 Comments :: 0 Trackbacks
引用:Quiz:who win in finally vs return?

废话就不多讲了,直接看看下面的例子。
1)static int Test()
        {
            int val = 1;
            try
            {
                return val;
            }
            finally
            {
                val = 2;
            }
        }
2)static int s_val;
       
static int Test()
        {
            s_val = 1;
           
try
            {
               
return s_val;
            }
           
finally
            {
                s_val = 2;
            }
        }

请问这两个例子最后的 return value 是什么?
     我们仔细看看这两个了例子就知道2)与1)的不同在于前者使用静态变量代替局部变量。那么他们之间有什么不同么?
答案是他们的return value 是一样的,都是1。
便于讲解,我们拿出他们的IL代码看看:


.method private hidebysig static int32  Test() cil managed
{
  
// Code size       16 (0x10)
  .maxstack  1
  .locals init ([
0] int32 val,
           [
1] int32 CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.
1  //int val=1
  IL_0002:  stloc.0
  .
try
  {
    IL_0003:  nop
    IL_0004:  ldloc.
0 //变量0(val) 入栈
    IL_0005:  stloc.1 // 这里建个中间隐藏变量1($ret)放回栈顶的值(val)。
    IL_0006:  leave.s    IL_000d
  }  
// end .try
  finally
  {
    IL_0008:  nop
    IL_0009:  ldc.i4.
2 //int val=2 并入栈
    IL_000a:  stloc.0 //返回栈顶的值付给变量0(val)
    IL_000b:  nop
    IL_000c:  endfinally
  }  
// end handler
  IL_000d:  nop
  IL_000e:  ldloc.
1 //取出变量1($ret)这就是放回值,但是这里我们可以看到val的值已经改变。
  IL_000f:  ret
// end of method Program::Test

.method private hidebysig static int32  Test1() cil managed
{
  
// Code size       28 (0x1c)
  .maxstack  1
  .locals init ([
0] int32 CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.
1 // 值1入栈。
  IL_0002:  stsfld     int32 ConsoleApp.Program::s_val //将栈顶值传给静态变量
  .try
  {
    IL_0007:  nop
    IL_0008:  ldsfld     int32 ConsoleApp.Program::s_val 
//取出静态变量
    IL_000d:  stloc.0 //从栈顶取出的值传给局部变量0的隐藏变量(这里静态变量不是局部变量0)
    IL_000e:  leave.s    IL_0019
  }  
// end .try
  finally
  {
    IL_0010:  nop
    IL_0011:  ldc.i4.
2 //同上
    IL_0012:  stsfld     int32 ConsoleApp.Program::s_val //存储静态变量为2
    IL_0017:  nop
    IL_0018:  endfinally
  }  
// end handler
  IL_0019:  nop
  IL_001a:  ldloc.
0 //取出局部变量0的值作为返回值。
  IL_001b:  ret
// end of method Program::Test1


这里无论是那种方式,都是生成一个隐藏变量存储返回值的,并不是直接返回变量的地址的。
如果大家多CLR的工作原理有所了解的话,应该不是很难理解,CLR对一个线程堆栈分配的是方法的局部变量和方法返回值。一个方法在线程堆栈中由它的实参开始到返回值结束。因此放回值是有自己的存储地址的。这样就可以解释上面的问题,看起来很像 { return i++ ;}
posted on 2008-06-13 22:52 KiMoGiGi 阅读(275) 评论(0)  编辑 收藏 引用 所属分类: C# / Winforms
只有注册用户登录后才能发表评论。