文章出處
View Code
文章列表
問題提出
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:\users\public\test.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"; } }
這里的執行順序是:
- 執行 return 之前的代碼
- 對 return 語句求值
- 執行 finally 中的代碼
- 在第 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 }
參考資料
- try-catch-finally(C# 參考)
- What really happens in a try { return x; } finally { x = null; } statement?
文章列表
全站熱搜