throw 不綁定 try-catch。它的唯一職責是「拋出異常對象」,由調用鏈上層決定是否捕獲、如何處理。濫用 try-catch 包裹業務邏輯會導致「異常控制流」反模式。
public bool ValidateUser(string userName, string password)
{
if (string.IsNullOrEmpty(userName))
throw new ArgumentException("值不能為 null 或空白。", nameof(userName));
if (string.IsNullOrEmpty(password))
throw new ArgumentException("值不能為 null 或空白。", nameof(password));
return _provider.ValidateUser(userName, password);
}
特點:快速失敗,保護核心邏輯不被髒數據污染,異常攜帶參數名便於診斷。
public void PlaceOrder(Order order)
{
if (order.Items.Count == 0)
throw new InvalidOperationException("訂單至少包含一個商品。");
if (order.TotalAmount > _customer.CreditLimit)
throw new BusinessRuleException("信用額度不足", "CREDIT_LIMIT_EXCEEDED", order.TotalAmount);
// ... 核心下單邏輯
}
自定義異常攜帶錯誤碼、上下文數據,上層 UI 可友好提示、日誌可精準分析。
public IEnumerable FilterByStatus(IEnumerable source, int statusFlag)
{
return statusFlag switch
{
0 => source.Where(p => p.EndTime > DateTime.Now), // 進行中
1 => source.Where(p => p.EndTime <= DateTime.Now), // 已結束
2 => source.Where(p => p.IsFeatured), // 推薦
_ => throw new ArgumentOutOfRangeException(nameof(statusFlag), statusFlag, "未知狀態標識")
};
}
避免「默認靜默忽略」導致數據錯誤難查,新增枚舉值時編譯器會提醒補全分支(若用模式匹配)。
public UserDto GetUserById(int id)
{
try
{
return _repo.GetById(id);
}
catch (SqlException ex) when (ex.Number == 2) // 超時
{
throw new DataAccessException("數據庫連接超時", "DB_TIMEOUT", ex);
}
catch (EntityNotFoundException ex)
{
throw new BusinessException($"用戶 {id} 不存在", "USER_NOT_FOUND", ex);
}
}
使用 when 過濾器精準捕獲,保留原始堆棧(throw; 而非 throw ex;),外層異常攜帶業務語義。
| 異常類型 | 適用場景 | 是否預期可捕獲處理 |
|---|---|---|
| ArgumentException / ArgumentNullException | 參數驗證失敗 | 否(編程錯誤,應修復代碼) |
| InvalidOperationException | 對象狀態不支持當前操作 | 視業務而定 |
| 自定義 BusinessException | 業務規則違規、用戶操作錯誤 | 是(UI 友好提示、記錄審計) |
| 自定義 DataAccessException | 數據層故障、超時、死鎖 | 是(重試、熔斷、降級) |
| NotImplementedException | 接口未實現、功能開發中 | 否(開發期標記) |
catch { throw; } 或 throw new BizEx("msg", ex);AggregateException 或記錄後再拋。// C# 8+ switch expression 自動覆蓋窮盡性檢查
var result = status switch
{
OrderStatus.Pending => "待處理",
OrderStatus.Paid => "已付款",
OrderStatus.Shipped => "已發貨",
OrderStatus.Completed => "已完成",
_ => throw new ArgumentOutOfRangeException(nameof(status), $"未知狀態: {status}")
};