基本語法
try
{
// 監控區塊:可能拋出例外的程式碼
}
catch (ExceptionType1 ex)
{
// 處理 ExceptionType1
}
catch (ExceptionType2 ex)
{
// 處理 ExceptionType2
}
// 可有多個 catch,但至多只有一個會執行
多重捕獲實戰範例
using System;
class MainClass
{
static void ProcessString(string str)
{
if (str == null)
throw new ArgumentNullException(nameof(str), "字串不可為 null");
if (str.Length == 0)
throw new ArgumentException("字串不可為空", nameof(str));
Console.WriteLine($"處理:{str}");
}
static void Main()
{
Console.WriteLine("輸出結果:");
try
{
string input = null; // 測試:改為 "" 或 "hello" 觀察不同 catch
ProcessString(input);
}
catch (ArgumentNullException ex)
{
Console.WriteLine($"[Null] {ex.Message}");
}
catch (ArgumentException ex)
{
Console.WriteLine($"[Argument] {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"[Other] {ex.Message}");
}
}
}
執行結果對照
| input 值 | 拋出例外 | 匹配 catch | 輸出 |
| null | ArgumentNullException | 第 1 個 | [Null] 字串不可為 null |
| "" | ArgumentException | 第 2 個 | [Argument] 字串不可為空 |
| "hello" | 無 | 無 | 處理:hello |
| (拋出 IOException) | IOException | 第 3 個 | [Other] ... |
捕獲順序鐵律:由子類別到父類別
// 錯誤:父類別在前,子類別永遠捕獲不到
catch (Exception ex) { }
catch (ArgumentNullException ex) { } // CS0160: 無法到達
// 正確:具體在前,一般在後
catch (ArgumentNullException ex) { }
catch (ArgumentException ex) { }
catch (Exception ex) { }
例外篩選器 (C# 6+)
try
{
RiskyOperation();
}
catch (IOException ex) when (ex.HResult == -2147024864) // 檔案不存在
{
Console.WriteLine("檔案不存在,建立新檔");
CreateNewFile();
}
catch (IOException ex) when (ex.HResult == -2147024891) // 存取被拒
{
Console.WriteLine("權限不足");
}
catch (IOException ex)
{
Console.WriteLine($"其他 IO 錯誤:{ex.Message}");
}
捕獲非 CLS 例外
// 僅捕獲 CLS-compliant 例外 (繼承自 Exception)
catch (Exception ex) { }
// 捕獲所有例外 (包含非 CLS,如 C++ 拋出的 int、SEH 例外)
catch { } // 極少使用,通常只在最頂層記錄用
實務建議
- 捕獲具體例外:只處理你知道如何恢復的例外
- 頂層捕獲 Exception 記錄:防止程式當機,記錄完整堆疊
- 避免空 catch:
catch { } 吞沒錯誤,除錯極難
- 使用 when 篩選:減少 catch 區塊數量,邏輯更清晰
- 非同步方法:
try/catch 包裹 await,否則例外會包裝在 Task 中
非同步範例
public async Task DownloadAsync(string url)
{
try
{
using var client = new HttpClient();
return await client.GetStringAsync(url);
}
catch (HttpRequestException ex)
{
Log(ex);
return "離線快取內容";
}
catch (TaskCanceledException)
{
return "請求逾時";
}
}