August 27, 2019

C# 异常处理最佳实践

异常类型

异常一般分为系统异常应用异常。系统异常有无法连接数据库,而应用异常是业务逻辑异常,比如授权失败。

在 C# 中异常基于 System.Exception,派生出 System.SystemExceptionSystem.ApplicationException。微软最初设计为 CLR 抛出的异常都继承自 System.SystemException,应用程序抛出的异常应当继承自 System.ApplicationException。但 .NET 框架类库(FCL) 没能很好地遵循这个原则。因此,目前存在的 System.SystemExceptionSystem.ApplicationException 主要用于兼容。

  1. 在实际业务中,不应该使用 System.SystemExceptionSystem.ApplicationException
  2. 不要在非顶层中捕获 System.Exception,除非你会在捕获后重新抛出
  3. 在对象不正确的时候,可使用 System.InvalidOperationExceptionSystem.ArgumentException 和其派生异常。例如给只读对象赋值
  4. 业务异常应该定义一个基于 System.Exception 的自定义异常,并基于自定义的异常再派生具体的异常。例如业务异常为 BusinessException:System.Exception,转账业务异常为 TransferFundsException:BusinessException
  5. 需要给异常填写异常描述
  6. 不要自己抛出 System.StackOverflowException 这类异常
  7. 并不是所有情况都需要使用 try catch 语句,可使用 if 提前判断是否抛出异常,以提高性能

使用 throwthrow ex 的区别

C# 中推荐使用 throw,原因是如果直接使用 throw ex 会清除原始的异常,将 ex 作为新的异常源,从而找不到真正的异常源。

建议只在最外层做捕获。

// 错误的用法
try
{
}
catch(Exception ex)
{
    throw ex;
}

// 正确的用法
try
{
}
catch
{
  throw;
}

// 正确的用法
try
{
}
catch(Exception ex)
{
  throw new Exception("message", ex);
}

// 正确的用法
throw new AppException("message");