| 特性 | C# | C++ |
| 例外型別 | 所有例外皆為 System.Exception 衍生類別 | 任意型別皆可拋出 (int, char*, class...) |
| finally 區塊 | 語言內建 finally,保證執行 | 無內建,需用 RAII / 析構函數模擬 |
| 系統例外 | 定義完善 (OverflowException, DivideByZeroException...) | 硬體/OS 例外 (SEH) 與 C++ 例外分離 |
| 檢查式例外 | 無 (全部非檢查式) | 無 (但可用規格文件約定) |
例外類別體系
System.Object
└─ System.Exception
├─ System.SystemException (CLR 擲出)
│ ├─ ArgumentException / ArgumentNullException
│ ├─ InvalidOperationException
│ ├─ NullReferenceException
│ ├─ IndexOutOfRangeException
│ ├─ DivideByZeroException
│ └─ OverflowException
└─ System.ApplicationException (使用者自訂基類,現建議直接繼承 Exception)
拋出例外
// 拋出現有例外
throw new ArgumentNullException(nameof(path), "路徑不可為空");
// 重新拋出 (保留堆疊追蹤)
catch (Exception ex)
{
Log(ex);
throw; // 必須無參數,否則堆疊重置
}
// 自訂例外最佳實踐
[Serializable]
public class BusinessRuleException : Exception
{
public string RuleCode { get; }
public BusinessRuleException(string ruleCode, string message)
: base(message) => RuleCode = ruleCode;
// 序列化建構函式 (跨 AppDomain/遠端需要)
protected BusinessRuleException(SerializationInfo info, StreamingContext ctx)
: base(info, ctx) => RuleCode = info.GetString("RuleCode");
public override void GetObjectData(SerializationInfo info, StreamingContext ctx)
{
base.GetObjectData(info, ctx);
info.AddValue("RuleCode", RuleCode);
}
}
例外傳播機制
- 拋出點 → 尋找包含的
try 區塊
- 依序檢查
catch 子句:第一個符合型別 (或其基類) 的處理
- 若無符合
catch,執行 finally (若有) → 繼續向外層傳播
- 若
finally 也拋出例外,原例外遺失 (新例外取代)
- 到達執行緒/進程頂層仍未處理 → 進程終止 (觸發
AppDomain.UnhandledException)
try-catch-finally 三種組合
| 形式 | 用途 | 範例 |
try-catch | 處理特定錯誤,繼續執行 | 檔案讀取失敗改用預設值 |
try-finally | 確保清理,不處理錯誤 (向上傳播) | 關閉檔案、釋放鎖 |
try-catch-finally | 處理錯誤 + 確保清理 | 資料庫交易:Commit/Rollback + 關閉連線 |
finally 執行保證實測
try {
Console.WriteLine("try");
goto EXIT; // 跳轉
}
finally {
Console.WriteLine("finally"); // 仍會執行!
}
EXIT:
Console.WriteLine("exit");
// 輸出:try → finally → exit
即使 return、break、continue、goto、throw,finally 仍保證執行。
常見陷阱
- 吞噬例外:
catch { } 或 catch (Exception) { } 不記錄、不重拋 → 錯誤隱形
- 拋出新例外丟失堆疊:
throw new Exception("msg", ex) 保留內部例外;throw ex 重置堆疊
- finally 中拋出例外:會掩蓋原本傳播的例外,極難除錯
- 非同步 void 方法例外無法捕捉:
async void 例外直接上報 SynchronizationContext
資源管理模式:using / IDisposable
// 編譯器展開為 try-finally
using (var fs = new FileStream("a.txt", FileMode.Open))
using (var sr = new StreamReader(fs))
{
return sr.ReadToEnd();
}
// 等價於:
FileStream fs = null;
try {
fs = new FileStream(...);
using (var sr = new StreamReader(fs)) { fs = null; return sr.ReadToEnd(); }
}
finally {
fs?.Dispose();
}
using 是 try-finally 的語法糖,確保 IDisposable 資源釋放。
- 上一篇文章: C# 流程控制完整指南:選擇、迴圈、跳轉、條件編譯與例外處理
- 下一篇文章: C# 例外處理實戰:try-catch-finally 結構、例外篩選與資源清理模式
Copyright ©
程式碼之家 All Rights Reserved