自定义异常的使用场景

看到一些文章说不要使用异常代替正常的控制流,对这个一直都不太清楚,随即查了下,做下笔记。

核心原则:区分预期错误(Expected Errors)意外异常(Unexpected Exceptions)

预期错误应当显示处理:输入验证、业务规则检查等都属于预期内的错误,应该通过返回值、状态码或结果对象明确传递。

假设需要验证用户输入内容合法性,有两种方式:

方式一:使用异常处理,不好的做法,会使调用方处理起来麻烦

// 通过抛出异常表示验证失败
public void ValidateEmail(string email)
{
if (!Regex.IsMatch(email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$"))
{
throw new InvalidEmailException("邮箱格式错误");
}
}
// 调用方必须用 try-catch 处理正常逻辑
try
{
ValidateEmail("invalid-email");
Console.WriteLine("邮箱有效");
}
catch (InvalidEmailException ex)
{
Console.WriteLine($"验证失败: {ex.Message}");
}

方式二:返回明确结果

// 返回一个结果对象,包含是否成功和错误信息
public ValidationResult ValidateEmail(string email)
{
bool isValid = Regex.IsMatch(email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$");
return new ValidationResult
{
IsValid = isValid,
ErrorMessage = isValid ? null : "邮箱格式错误"
};
}
// 调用方直接处理结果,无需 try-catch
var result = ValidateEmail("invalid-email");
if (result.IsValid)
{
Console.WriteLine("邮箱有效");
}
else
{
Console.WriteLine($"验证失败: {result.ErrorMessage}");
}

滥用异常的坏处

  1. 性能问题,异常处理成本高昂,CLR需要手机堆栈跟踪(Stack Trace)、展开调用栈,相比较条件判断,要慢数百倍。
  2. 代码可读性低,使用try-catch处理正常流程,会让其他人误以为是意外错误,而非预期业务逻辑分支。
  3. 破坏代码结构,正常的控制流被打断,其他人不得不处理异常,导致代码难以维护

所有业务流程中的错误都不属于异常吗?

非也,本质还是判断错误的性质:是预期内的业务规则失败,还是需要中断当前流程的严重错误。比如:

场景一:某些业务错误需要立即终止当前操作,且不适合通过返回值逐层传递,此时异常是更直接的选择。
场景二:需统一处理的特定错误类型
通过自定义异常,可在全局异常过滤器中统一处理特定业务错误,返回标准化响应。例如:

// 自定义异常
public class InsufficientBalanceException : Exception
{
public decimal RequiredAmount { get; }
public InsufficientBalanceException(decimal required)
: base($"余额不足,需支付 {required}")
=> RequiredAmount = required;
}
// 全局异常过滤器
public class BusinessExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context.Exception is InsufficientBalanceException ex)
{
context.Result = new JsonResult(new
{
Code = 400,
Message = ex.Message,
RequiredAmount = ex.RequiredAmount
});
context.ExceptionHandled = true;
}
}
}

在判断是否使用自定义异常前,先问自己以下几个问题:

  1. 是否属于不可恢复的错误?
  2. 是否需要跨多层传递错误?
  3. 是否不属于预期内的业务规则失败?
  4. 是否需要强制调用方处理此错误?
  5. 发生频率是否很低?
    若有半数以上结果为“是”,则说明适合自定义异常。
posted @   南山有榛  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示