finally 區塊在下列情況**保證執行**:
try 正常結束try 中 return/break/continuecatch 區塊執行完畢 (含 catch 中 return)catch 區塊重新拋出例外 (throw;)catch,例外向上傳播前不執行情況:Environment.FailFast、進程被強制終止、無限迴圈、堆疊溢位。
using System;
public class MainClass
{
static void Main()
{
int i = 123;
string s = "Some string";
object o = s; // 裝箱
try
{
i = (int)o; // 執行時拋出 InvalidCastException
}
catch
{
Console.WriteLine("捕獲例外:InvalidCastException");
}
finally
{
Console.WriteLine($"finally 區塊執行,i = {i}"); // i 保持 123
}
Console.WriteLine("程式繼續執行");
Console.Read();
}
}
捕獲例外:InvalidCastException
finally 區塊執行,i = 123
程式繼續執行
// 模式一:try/finally (C# 1.0 風格)
StreamWriter sw = null;
try
{
sw = new StreamWriter("data.txt");
sw.WriteLine("重要資料");
}
finally
{
if (sw != null) sw.Close(); // 必須檢查 null
}
// 模式二:using 敘述 (C# 2.0+ 推薦,編譯器自動產生 try/finally)
using (var sw = new StreamWriter("data.txt"))
{
sw.WriteLine("重要資料");
} // 這裡自動呼叫 sw.Dispose() -> Close()
// 模式三:C# 8+ using 宣告 (無大括號)
using var sw = new StreamWriter("data.txt");
sw.WriteLine("重要資料");
// 方法結束自動 Dispose
// 巢狀 using (C# 8 前)
using (var conn = new SqlConnection(cs))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT * FROM Users";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read()) { /* ... */ }
}
}
// C# 8+ 扁平化
using var conn = new SqlConnection(cs);
using var cmd = conn.CreateCommand();
conn.Open();
cmd.CommandText = "SELECT * FROM Users";
using var reader = cmd.ExecuteReader();
while (reader.Read()) { /* ... */ }
| 陷阱 | 後果 | 解決 |
|---|---|---|
| finally 中拋出例外 | 遮蔽 try/catch 原始例外 | finally 僅做清理,不拋出例外 |
| finally 中 return | 吞沒 try/catch 的 return 值/例外 | finally 禁止 return |
| 資源未檢查 null | NullReferenceException 掩蓋原錯誤 | 使用 using 或 null 條件運算子 |
| 關閉順序錯誤 | 資料遺失、連線洩漏 | 反向順序關閉:Reader → Command → Connection |
public async Task FetchAsync(string url)
{
using var client = new HttpClient();
try
{
return await client.GetStringAsync(url);
}
catch (HttpRequestException ex)
{
Log(ex);
throw; // 重新拋出
}
finally
{
// 這裡執行於 await 完成後,client 已在 using 範圍外自動 Dispose
// 可做額外記錄:Metrics.RecordCompletion();
}
}
using** 管理實作 IDisposable 的資源finally 僅用於**非受控資源清理**或**不可用 using 的情況**finally **不拋出例外、不返回**await 前後皆可用 try/finally,但 using 範圍需涵蓋 awaitInnerException 與堆疊追蹤