🔄 传统模式痛点:每个端点都要结果检查 假设我们有一个返回操作结果的接口:
app.MapGet("/", async () =>
{
var result = await InvokeAsync();
if(result.IsSuccess)
{
return TypedResults.BadRequest();
}
return TypedResults.Ok();
});
在每个端点中重复进行这种检查实在令人抓狂。
🛠️ 重构方案:通用结果模式
public readonly struct Result<TValue, TError>
{
private readonly TValue? _value;
private readonly TError? _error;
// 构造函数与属性定义...
public static implicit operator Result<TValue, TError>(TValue value) => new(value);
public static implicit operator Result<TValue, TError>(TError error) => new(error);
}
关键改进:通过隐式操作符简化类型转换:
// 优化前
return Result<Success, NotFound>.Failure(new NotFound());
// 优化后
return new NotFound();
public sealed class ErrorResult<TError>(TError error) : IResult
{
public Task ExecuteAsync(HttpContext httpContext)
{
httpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
return httpContext.Response.WriteAsJsonAsync(error);
}
}
public sealed class EndpointResult<TValue, TError> : IResult
{
private readonly IResult _result;
public static implicit operator EndpointResult<TValue, TError>(Result<TValue, TError> result)
=> result.IsSuccess
? new EndpointResult<TValue, TError>(TypedResults.Ok(result.Value))
: new EndpointResult<TValue, TError>(new ErrorResult<TError>(result.Error));
}
🚀 使用效果对比 重构前代码
async Task<Result<Success, NotFound>> UpdateNoteAsync(Guid id, string value)
{
var note = await _dbContext.Notext.FindAsync(id);
if(note == null)
{
return Result<Success, NotFound>.Failure(new NotFound())
}
note.Value = value;
await _dbContext.SaveChangesAsync();
return Result<Success, Error>.Success(new Success())
}
重构后代码
async Task<EndpointResult<Success, Error>> InvokeAsync()
{
return await InternalInvokeAsync();
}
核心收益:
✅ 完全消除结果状态检查
✅ 代码量减少60%
✅ 统一错误处理流程
🧩 方案优势解析 | 特性 | 传统方案 | 新方案 | |---------------------|--------------------------|---------------------------| | 错误处理 | 每个端点重复检查 | 自动转换 | | 类型安全 | 需显式类型声明 | 隐式类型转换 | | 代码可维护性 | 高耦合 | 解耦业务与HTTP响应 | | 扩展性 | 修改需全局调整 | 新增错误类型即生效 |
🔧 实战应用场景
🛠️ 进阶扩展建议
// 扩展自定义HTTP状态码
public sealed class CustomErrorResult<TError>(TError error, HttpStatusCode code) : IResult
{
public Task ExecuteAsync(HttpContext context)
{
context.Response.StatusCode = (int)code;
return context.Response.WriteAsJsonAsync(error);
}
}
// 使用示例
return new CustomErrorResult<ErrorType>(error, HttpStatusCode.NotFound);
技术思考:
这个方案本质上是通过语言特性与类型系统的结合,将横切关注点(结果处理)转化为编译期约束。当隐式转换遇上结果模式,我们不仅消除了模板代码,更构建了具有自描述性的领域语言——这正是现代C#的演化方向。