zoukankan      html  css  js  c++  java
  • Try..Finally..相信自己的眼睛

    问题提出

    1       try 
    2       { 
    3         return x; 
    4       }
    5       finally 
    6       { 
    7         x = null; 
    8       }

    上面这段代码到底怎么执行的?

    try..catch..finally 介绍

    在MSDN中,try..catch..finally 的介绍如下:

    • finally 块用于清除 try 块中分配的任何资源,以及运行任何即使在发生异常时也必须执行的代码。 控制总是传递给 finally 块,与 try 块的退出方式无关。
    • catch 用于处理语句块中出现的异常,而 finally 用于保证代码语句块的执行,与前面的 try 块的退出方式无关。
    • catch 和 finally 一起使用的常见方式是:在 try 块中获取并使用资源,在 catch 块中处理异常情况,并在 finally 块中释放资源。

    典型用法:

     1     void ReadFile(int index)
     2     {
     3       string path = @"c:userspublic	est.txt";
     4       char[] buffer = new char[10];
     5 
     6       StreamReader file = new StreamReader(path);
     7       try
     8       {
     9         file.ReadBlock(buffer, index, buffer.Length);
    10       }
    11       catch (IOException e)
    12       {
    13         Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
    14       }
    15       finally
    16       {
    17         if (file != null)
    18         {
    19           file.Close();
    20         }
    21       }
    22     }

    通常 finally 中的代码只负责清理资源。

    那么,如果 finally 中包含业务逻辑,try..finally..的执行顺序会对业务逻辑有怎样的影响呢?

    try..finally 的执行顺序

    回到问题,

        void Main()
        {
          Console.WriteLine(TestTryFinally());
        }
    
        public string TestTryFinally()
        {
          string x = "init";
          try
          {
            x = "try";
            return x;
          }
          finally
          {
            x = "finally";
          }
        }

    这里的执行顺序是:

    1. 执行 return 之前的代码
    2. 对 return 语句求值
    3. 执行 finally 中的代码
    4. 在第 2 步中的求值结果被返回

    所以,具体是否对返回值有影响,得看 x 变量的类型。如果是不可变类型,则 finally 中的代码对 return 的求值结果没有任何影响。而如果是可变类型,则 finally 中的代码会改变 return 求值结果的内容。

    上述代码,在 x 类型为 string 时,返回值为 "try"。

    查看 IL 代码,

     1 IL_0000:  ldarg.0     
     2 IL_0001:  call        UserQuery.TestTryFinally
     3 IL_0006:  call        System.Console.WriteLine
     4 
     5 TestTryFinally:
     6 IL_0000:  ldstr       "init"
     7 IL_0005:  stloc.0     // x
     8 IL_0006:  ldstr       "try"
     9 IL_000B:  stloc.0     // x
    10 IL_000C:  ldloc.0     // x
    11 IL_000D:  stloc.1     // CS$1$0000
    12 IL_000E:  leave.s     IL_0017
    13 IL_0010:  ldstr       "finally"
    14 IL_0015:  stloc.0     // x
    15 IL_0016:  endfinally  
    16 IL_0017:  ldloc.1     // CS$1$0000
    17 IL_0018:  ret    

    发现在 stloc.1 处会创建 CS$1$0000 临时变量来存储 return 返回值。

    从程序集反编译代码查看结果,程序已经被优化。

     1 // ConsoleApplication11_TryFinallyTest.Program
     2 public string TestTryFinally()
     3 {
     4     string result;
     5     try
     6     {
     7         string x = "try";
     8         result = x;
     9     }
    10     finally
    11     {
    12     }
    13     return result;
    14 }

    更多测试结果

      1 using System;
      2 using System.Text;
      3 
      4 namespace ConsoleApplication11_TryFinallyTest
      5 {
      6   class Program
      7   {
      8     static void Main(string[] args)
      9     {
     10       Console.WriteLine(MethodA());
     11       Console.WriteLine(a);
     12 
     13       Console.WriteLine(MethodB().ToString());
     14       Console.WriteLine(b.ToString());
     15 
     16       Console.WriteLine(MethodC());
     17       Console.WriteLine(c);
     18 
     19       Console.WriteLine(MethodD().ToString());
     20       Console.WriteLine(d.ToString());
     21 
     22       Console.WriteLine(MethodE().ToString());
     23       Console.WriteLine(e.ToString());
     24 
     25       Console.ReadKey();
     26     }
     27 
     28     static string a;
     29     static string MethodA()
     30     {
     31       try
     32       {
     33         a = "tryA";
     34         return a;
     35       }
     36       finally
     37       {
     38         a = "finallyA";
     39       }
     40     }
     41 
     42     static StringBuilder b = new StringBuilder();
     43     static StringBuilder MethodB()
     44     {
     45       try
     46       {
     47         b.Append("tryB");
     48         return b;
     49       }
     50       finally
     51       {
     52         b.Append("finallyB");
     53       }
     54     }
     55 
     56     static int c;
     57     static int MethodC()
     58     {
     59       try
     60       {
     61         c = 3;
     62         return c;
     63       }
     64       finally
     65       {
     66         c = 4;
     67       }
     68     }
     69 
     70     static Person d;
     71     static Person MethodD()
     72     {
     73       try
     74       {
     75         d = new Person() { Name = "tryD" };
     76         return d;
     77       }
     78       finally
     79       {
     80         d = new Person() { Name = "finallyD" };
     81       }
     82     }
     83 
     84     static Person e;
     85     static Person MethodE()
     86     {
     87       e = new Person() { Name = "E" };
     88       try
     89       {
     90         e.Name = "tryE";
     91         return e;
     92       }
     93       finally
     94       {
     95         e.Name = "finallyE";
     96       }
     97     }
     98 
     99     class Person
    100     {
    101       public string Name { get; set; }
    102       public override string ToString()
    103       {
    104         return Name;
    105       }
    106     }
    107   }
    108 }
    View Code

    参考资料

  • 相关阅读:
    Codeforces 653C Bear and Up-Down【暴力】
    Codeforces 653B Bear and Compressing【DFS】
    Codeforces 653B Bear and Compressing【DFS】
    Codeforces 653A Bear and Three Balls【水题】
    Codeforces 645D Robot Rapping Results Report【拓扑排序+二分】
    Codeforces 645C Enduring Exodus【二分】
    软件工程作业01
    《构建之法》阅读笔记5
    登录界面代码
    《构建之法》读书笔记4
  • 原文地址:https://www.cnblogs.com/gaochundong/p/try_finally_statement.html
Copyright © 2011-2022 走看看