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

catch 區塊中 throw new Exception 的意義與最佳實務

     編輯:關於.NET

核心語法

throw new Exception(string message);
throw new Exception(string message, Exception innerException);
  • throw:明確拋出例外。
  • Exception(string, Exception):使用指定錯誤訊息與內部例外參考初始化新例外 (MSDN 定義)。

為何在 catch 中重新拋出新例外?

  1. 保留原始堆疊與語境:將捕獲的例外作為 innerException 封裝在新例外中,完整保留原始錯誤鏈結,利於除錯追蹤根因。
  2. 轉譯/豐富錯誤資訊:在拋出新例外前,可記錄日誌、附加業務語境 (如使用者 ID、操作代碼)、轉換為更具體的自訂例外型別 (如 BusinessRuleException),讓上層呼叫者能針對性處理。
  3. 避免敏感資訊外洩:捕獲底層例外 (如 SQL 連線失敗) 後,拋出不含敏感細節的高層例外 (如「資料存取暫時失敗,請稍後再試」)。

三種 catch 區塊處理策略比較

策略程式碼範例適用情境
1. 直接處理並結束 (不再拋出)
catch (Exception ex) {
    MessageBox.Show(ex.Message);
    Log.Error(ex);
}
頂層 UI、背景工作、不需上層知情的獨立作業
2. 通知使用者/記錄後「吞掉」例外 (空 catch)
catch (Exception) {
    // 故意忽略,視為預期行為
}
極少數「預期會失敗且可安全忽略」的情境 (需詳加註解)
3. 記錄/轉換後 重新拋出新例外
catch (SqlException ex) {
    Log.Error(ex);
    throw new DataAccessException("資料庫暫時無法連線", ex);
}
分層架構中,下層錯誤需轉譯為上層可理解的業務例外;或需保留完整呼叫堆疊供上層判斷

程式碼範例:自訂例外與內部例外鏈結

int num = Convert.ToInt32(textBox1.Text);
try
{
    if (num == 0)
        throw new ArgumentNullException("輸入不可為零!");
    if (num == 1)
        throw new Exception("輸入不可為一!");
}
catch (ArgumentNullException ex)
{
    MessageBox.Show($"參數錯誤:{ex.Message}");
}
catch (Exception ex)
{
    MessageBox.Show($"一般錯誤:{ex.Message}");
}

// 進階:捕獲後轉拋自訂例外
try
{
    // 呼叫底層資料存取
    repository.Save(entity);
}
catch (SqlException sqlEx) when (sqlEx.Number == 1205) // 死結
{
    Log.Warn(sqlEx, "偵測到死結,嘗試重試...");
    throw new ConcurrencyException("資料衝突,請重新整理後再試", sqlEx); // 保留 sqlEx 為 InnerException
}
catch (Exception ex)
{
    Log.Error(ex, "未預期的儲存失敗");
    throw; // 直接重拋原例外 (保留完整堆疊)
}

關鍵觀念釐清

  • throw vs throw ex:throw; 保留原始堆疊追蹤;throw ex; 會重設堆疊起點為該行,**務必使用 throw; 或封裝為新例外 (throw new MyEx(msg, ex))**。
  • 何時明確 throw?
    1. 測試模擬難以重現的例外 (如 OutOfMemoryException)。
    2. 自訂業務規則違反 (如「庫存不足」) 需主動拋出自訂例外型別。
  • catch 區塊不是「錯誤處理」的終點,而是「錯誤轉譯」的樞紐:決定是就地處理、轉譯上拋、或記錄後靜默。

最佳實務建議

  1. 盡量捕獲具體例外型別,避免 catch (Exception) 吞噬所有錯誤。
  2. 重新拋出時,**永遠保留 innerException**,除非有極強理由切斷鏈結。
  3. 定義清晰的自訂例外階層 (繼承 ApplicationException 或 Exception),讓呼叫者能精準 catch。
  4. 記錄日誌時包含完整 ex.ToString() (含堆疊、內部例外),而非僅 ex.Message。
  5. 避免在 finally 或 catch 中拋出新例外覆蓋原始錯誤,若必要請使用 ExceptionDispatchInfo.Capture(ex).Throw() (NET 4.5+) 保留堆疊。

總結

catch 中 throw new Exception(msg, innerEx) 的核心價值在於錯誤語境轉譯與堆疊保留。善用內部例外鏈結、自訂例外型別、精準捕獲與完整日誌,能建立可維護、可診斷的異常處理體系。

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