首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 例外處理機制深度解析:與 C++ 差異、例外傳播與 finally 語意

     編輯:關於C#

C# vs 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);
    }
}

例外傳播機制

  1. 拋出點 → 尋找包含的 try 區塊
  2. 依序檢查 catch 子句:第一個符合型別 (或其基類) 的處理
  3. 若無符合 catch,執行 finally (若有) → 繼續向外層傳播
  4. 若 finally 也拋出例外,原例外遺失 (新例外取代)
  5. 到達執行緒/進程頂層仍未處理 → 進程終止 (觸發 AppDomain.UnhandledException)

try-catch-finally 三種組合

特性C#C++
例外型別所有例外皆為 System.Exception 衍生類別任意型別皆可拋出 (int, char*, class...)
finally 區塊語言內建 finally,保證執行無內建,需用 RAII / 析構函數模擬
系統例外定義完善 (OverflowException, DivideByZeroException...)硬體/OS 例外 (SEH) 與 C++ 例外分離
檢查式例外無 (全部非檢查式)無 (但可用規格文件約定)

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 資源釋放。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
形式用途範例
try-catch處理特定錯誤,繼續執行檔案讀取失敗改用預設值
try-finally確保清理,不處理錯誤 (向上傳播)關閉檔案、釋放鎖
try-catch-finally處理錯誤 + 確保清理資料庫交易:Commit/Rollback + 關閉連線