在.NET开发中,异常处理虽广泛使用,但可能带来性能损耗与代码复杂度。本文将揭秘如何通过Result模式替代异常,构建高可读、易维护且性能更优的.NET应用。
传统异常处理依赖try/catch
代码块,但存在显著缺陷:
public async Task<ShipmentResponse> CreateAsync(
CreateShipmentCommand request,
CancellationToken cancellationToken)
{
// 检查订单是否已存在
if (await CheckExistingShipment(request.OrderId))
{
throw new ShipmentAlreadyExistsException(request.OrderId); // 异常中断流程
}
// 正常业务逻辑
var shipment = CreateNewShipment(request);
return shipment.MapToResponse();
}
痛点分析:
• 不可预测性:无法通过方法签名预判可能抛出的异常
• 性能损耗:异常处理机制存在性能开销(.NET 9虽有优化但仍需注意)
• 代码碎片化:catch
语句打断代码线性阅读体验
Result模式通过封装操作结果(成功/失败)实现显式错误处理:
// 泛型Result类定义
public class Result<T>
{
public bool IsSuccess { get; }
public T? Value { get; }
public string? Error { get; }
private Result(bool isSuccess, T? value, string? error)
{
IsSuccess = isSuccess;
Value = value;
Error = error;
}
public static Result<T> Success(T value) => new(true, value, null);
public static Result<T> Failure(string error) => new(false, default, error);
}
改造后的业务逻辑:
public async Task<Result<ShipmentResponse>> CreateAsync(
CreateShipmentCommand request,
CancellationToken cancellationToken)
{
if (await CheckExistingShipment(request.OrderId))
{
return Result.Failure<ShipmentResponse>($"订单{request.OrderId}物流已存在"); // 显式返回错误
}
var shipment = CreateNewShipment(request);
return Result.Success(shipment.MapToResponse()); // 明确返回成功结果
}
API端点处理:
private static async Task<IResult> HandleRequest(
CreateShipmentRequest request,
IShipmentService service)
{
var result = await service.CreateAsync(request.ToCommand());
return result.IsSuccess
? Results.Ok(result.Value)
: Results.Conflict(result.Error); // 根据Result状态返回对应HTTP响应
}
NuGet包ErrorOr
提供更强大的Result实现:
public async Task<ErrorOr<ShipmentResponse>> ProcessOrder(
CreateShipmentCommand command)
{
if (await CheckExistingShipment(command.OrderId))
{
return Error.Conflict(code: "SHIPMENT_EXISTS", description: "物流记录已存在"); // 预定义错误类型
}
return CreateNewShipment(command).ToResponse(); // 自动包装为成功结果
}
统一错误处理中间件:
public static class ErrorHandler
{
public static IResult ToProblem(this Error error)
{
var statusCode = error.Type switch
{
ErrorType.Conflict => StatusCodes.Status409Conflict,
ErrorType.Validation => StatusCodes.Status400BadRequest,
// 其他错误类型映射...
_ => StatusCodes.Status500InternalServerError
};
return Results.Problem(
statusCode: statusCode,
detail: error.Description);
}
}
推荐使用Result模式:
• 业务流程中的预期错误(如订单重复)
• 需要明确错误类型传递的跨层调用
• 高频调用的核心业务逻辑
保留异常处理:
• 全局异常捕获(通过.NET 8的IExceptionHandler
)
internal sealed class GlobalExceptionHandler : IExceptionHandler
{
public async ValueTask<bool> TryHandleAsync(
HttpContext context,
Exception exception,
CancellationToken cancellationToken)
{
// 记录日志并返回标准化错误响应
await context.WriteAsJsonAsync(new ProblemDetails
{
Title = "服务器错误",
Status = StatusCodes.Status500InternalServerError
});
return true;
}
}
• 第三方库集成(保持与传统库的兼容性)
• 领域模型守卫验证(防御非预期状态)
Result模式优势:
• ✅ 显式错误路径,提升代码可读性
• ⚡ 减少异常抛出,优化性能指标
• 🧪 便于单元测试(无需模拟异常抛出)
潜在权衡:
• ➕ 需统一团队规范以避免不同实现方式混杂
• ➖ 深度调用链需逐层传递Result对象
最佳实践建议:
ErrorOr
等成熟库替代自行封装