KiMoGiGi 技术文集

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

IT博客 首页 联系 聚合 管理
  185 Posts :: 14 Stories :: 48 Comments :: 0 Trackbacks
Quiz:who win in finally vs return? 中,我们看到的例子是以string作为返回值。

虽然string是引用类型,由于string的“ immutability ”特性,操作它的行为结果如同Value Type。

因此在上文中的结果只说明Value Type的显示结果,如果把返回值改为引用类型呢?

现有代码如下

class Program
    {
        
static void Main(string[] args)
        {
            Console.WriteLine(Try2().Str);
        }

        
static MyClass2 Try2()
        {
            MyClass2 my2 
= new MyClass2();
            
try
            {
                my2.Str 
= "try";
                
return my2;
            }
            
finally
            {
                my2.Str 
= "final";
            }
        }
    }

    
class MyClass2
    {
        
public string Str { getset; }
    }

返回结果是“final”。

看看编译器把这段Try2这个方法转成了什么样的IL?

.method private hidebysig static class TryFinally.MyClass2 Try2() cil managed
    {
        .maxstack 
2
        .locals init (
            [
0class TryFinally.MyClass2 my2,              //在方法里面有2个参数,1个是my2;第二个是IL生成的变量,用于返回结果
            [1class TryFinally.MyClass2 CS$1$0000)
        L_0000: nop 
        L_0001: newobj instance 
void TryFinally.MyClass2::.ctor()
        L_0006: stloc.
0 
        L_0007: nop 
        L_0008: ldloc.
0         //把第一个参数my2推出栈顶
        L_0009: ldstr "try"     //加载"try"字符串
        L_000e: callvirt instance void TryFinally.MyClass2::set_Str(string//调用my2的set_Str方法,即为Str属性赋值"try"。
        L_0013: nop 
        L_0014: ldloc.
0         //把第一个参数my2推出栈顶
        L_0015: stloc.1         //把my2保存到CS$1$0000,即返回值
        L_0016: leave.s L_0027  //转到 L_0027指令。(但注意最后一句声明.try L_0007 to L_0018 finally handler L_0018 to L_0027,因此在leave之前还需要执行L_0018 to L_0027)
        L_0018: nop 
        L_0019: ldloc.
0         //把第一个参数my2推出栈顶
        L_001a: ldstr "final"   //加载"final"字符串
        L_001f: callvirt instance void TryFinally.MyClass2::set_Str(string//调用my2的set_Str方法,即为Str属性赋值"final"。这里虽然没有操作CS$1$0000,但引用类型嘛,CS$1$0000的值当然影响了。
        L_0024: nop 
        L_0025: nop 
        L_0026: endfinally      
        L_0027: nop             
//finally结束
        L_0028: ldloc.1         //最后把CS$1$0000返回。在这里CS$1$0000的Str已经是final了
        L_0029: ret 
        .
try L_0007 to L_0018 finally handler L_0018 to L_0027
    }



从上面IL代码看出,处理流程跟以前处理str是一样的,只是因为引用类型特性的原因,返回的结果就跟值类型有所不同。

另外我们还看到IL处理try finally的时候,.NET1.1和.NET2.0生成的IL有少许不同。Quiz:who win in finally vs return? 中的是.NET1.1的版本。此为.NET2.0的版本。

posted on 2008-06-14 11:36 KiMoGiGi 阅读(227) 评论(0)  编辑 收藏 引用 所属分类: C# / Winforms
只有注册用户登录后才能发表评论。