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

C# 例外處理機制與自訂例外類別完整實作指南

     編輯:關於C#

例外處理是建構健壯應用程式的基石。C# 採用 try/catch/finally 結構化例外處理 (SEH),所有例外類別繼承自 System.Exception。本文系統說明標準例外階層、自訂例外設計模式、最佳實務與常見反模式。

標準例外類別階層


System.Object
  └─ System.Exception
       ├─ System.SystemException (CLR 擲回)
       │    ├─ ArgumentException / ArgumentNullException / ArgumentOutOfRangeException
       │    ├─ InvalidOperationException
       │    ├─ NullReferenceException
       │    ├─ IndexOutOfRangeException
       │    ├─ DivideByZeroException
       │    └─ ... (其他執行階段錯誤)
       └─ System.ApplicationException (使用者程式碼擲回,建議直接繼承 Exception)
            └─ (自訂例外類別)

基本 try/catch/finally 結構


try
{
    // 可能拋出例外的程式碼
    int result = 10 / int.Parse(userInput);
}
catch (DivideByZeroException ex)
{
    // 處理特定例外
    Log.Error("除零錯誤", ex);
    throw new BusinessException("無法除以零", ex); // 包裝重新拋出
}
catch (FormatException ex) when (userInput == null) // C# 6+ 例外篩選器
{
    Log.Warn("輸入為空");
}
catch (Exception ex) // 捕獲其餘例外 (最後)
{
    Log.Fatal("未預期錯誤", ex);
    throw; // 保留堆疊追蹤重新拋出
}
finally
{
    // 無條件執行:資源釋放、清理
    CleanupResources();
}

自訂例外類別設計模式

標準四建構子模式 (可序列化、支援內部例外)


[Serializable]
public class BusinessException : Exception
{
    public string ErrorCode { get; } // 擴充屬性:錯誤代碼、HTTP 狀態碼等

    // 1. 無參數
    public BusinessException() : base() { }

    // 2. 訊息
    public BusinessException(string message) : base(message) { }

    // 3. 訊息 + 內部例外 (重要:保留原始堆疊)
    public BusinessException(string message, Exception inner) : base(message, inner) { }

    // 4. 序列化建構子 (跨 AppDomain/遠端通訊必要)
    protected BusinessException(SerializationInfo info, StreamingContext context) : base(info, context)
    {
        ErrorCode = info.GetString(nameof(ErrorCode));
    }

    // 擴充建構子:攜帶錯誤代碼
    public BusinessException(string message, string errorCode, Exception inner = null) 
        : base(message, inner)
    {
        ErrorCode = errorCode;
    }

    // 重寫 GetObjectData 支援序列化
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue(nameof(ErrorCode), ErrorCode);
    }
}

使用範例


public void ValidateInput(string input)
{
    if (string.IsNullOrWhiteSpace(input))
        throw new BusinessException("輸入不可為空", "ERR_EMPTY_INPUT");
    
    if (input.Length > 27)
        throw new BusinessException($"輸入長度 {input.Length} 超過上限 27", "ERR_LENGTH_EXCEED");
}

public void Process()
{
    try
    {
        ValidateInput(Console.ReadLine());
    }
    catch (BusinessException ex)
    {
        Console.WriteLine($"[{ex.ErrorCode}] {ex.Message}");
        // 記錄日誌、回傳 API 錯誤回應等
    }
}

例外處理最佳實務

原則說明反模式
僅捕獲可處理的例外捕獲 Exception 應極少見,通常在最外層記錄後終止catch(Exception) { } 吞沒錯誤
保留堆疊追蹤重新拋出用 throw; 而非 throw ex;throw ex; 重設堆疊
使用 finally/using 釋放資源檔案、連線、鎖定、非受控資源catch 區塊關閉資源,finally 未處理
避免控制流程使用例外例外成本高,正常邏輯用回傳值/模式比對用 TryParse 而非 try/catch Parse
提供豐富內容自訂例外攜帶 ErrorCode、EntityId、Timestamp 等僅有 Message 字串
非同步正確傳播await 會自動拆封 AggregateException.Result 導致同步阻塞與 AggregateException

進階主題

例外篩選器


catch (SqlException ex) when (ex.Number == 2627) // 唯一鍵衝突
{
    throw new BusinessException("資料重複", "ERR_DUP_KEY", ex);
}

全域例外處理

  • WinForms: Application.ThreadException + AppDomain.CurrentDomain.UnhandledException
  • ASP.NET Core: app.UseExceptionHandler / UseDeveloperExceptionPage / Middleware
  • WPF: DispatcherUnhandledException + AppDomain.UnhandledException

效能考量

  • 例外擲回/捕獲成本約微秒級,避免在迴圈/高頻路徑使用例外控制流程。
  • 熱路徑改用 TryParse、TryGetValue、Result<T> (Discriminated Union) 模式。

常見標準例外對照表

例外類別適用情境HTTP 狀態碼對應
ArgumentNullException參數為 null400 Bad Request
ArgumentOutOfRangeException參數超出有效範圍400 Bad Request
InvalidOperationException物件狀態不適合操作409 Conflict / 400
KeyNotFoundException字典/集合找不到鍵404 Not Found
NotSupportedException功能不支援405 Method Not Allowed / 501
UnauthorizedAccessException權限不足401/403
TimeoutException作業逾時408/504

建立清晰的例外階層、遵循標準建構子模式、善用 finally/using 確保資源釋放、在架構邊界統一轉換為領域例外,能讓錯誤訊息更具可行動性,大幅降低除錯與維護成本。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved