CQRS架构下C#如何实现Handle方法多类型泛型Response返回?
C# CQRS中实现多类型返回的方案
问题场景
我用C#开发CQRS架构系统,现有一段Handle方法代码:
public async Task<Response<SaleProducts>> Handle(CreateSaleProductCommand request, CancellationToken cancellationToken) { var newEntity = MyCustomerMapper.Mapper.Map<SaleProducts>(request); if (newEntity is null) throw new ApplicationException("There is a problem in mapper"); var itemToReturn = await _repositoryCommand.AddProductToSaleAsync(newEntity); if(itemToReturn != null) { itemToReturn.Product = await _productQueryRepository.GetByIdAsync(itemToReturn.ProductId); return new Response<SaleProducts>(itemToReturn); } else throw new ApplicationException("There is a problem when saving the product"); }
这个方法最终返回Response<SaleProducts>类型。现在想给_repositoryCommand.AddProductToSaleAsync加验证逻辑:验证通过返回SaleProducts,不通过返回bool或string这类类型,想知道能不能实现类似public async Task<Response<SaleProducts | bool>> Handle(...)这种多类型返回的写法。
可行实现方案
C#没法直接在泛型参数里用SaleProducts | bool这种联合类型语法(C# 12虽然引入联合类型,但只能先声明类型再用,不能直接嵌在泛型里),但可以通过下面几种方式实现需求:
1. 自定义结果类
自己写个统一的结果类,把成功数据、失败状态/消息都包进去:
public class OperationResult<T> { public bool IsSuccess { get; set; } public T? SuccessData { get; set; } public string? ErrorMessage { get; set; } // 静态方法方便创建实例 public static OperationResult<T> Success(T data) => new() { IsSuccess = true, SuccessData = data }; public static OperationResult<T> Failure(string message) => new() { IsSuccess = false, ErrorMessage = message }; }
然后把AddProductToSaleAsync的返回类型改成Task<OperationResult<SaleProducts>>,Handle方法调整成这样:
public async Task<Response<SaleProducts>> Handle(CreateSaleProductCommand request, CancellationToken cancellationToken) { var newEntity = MyCustomerMapper.Mapper.Map<SaleProducts>(request); if (newEntity is null) throw new ApplicationException("There is a problem in mapper"); var result = await _repositoryCommand.AddProductToSaleAsync(newEntity); if(result.IsSuccess) { var itemToReturn = result.SuccessData!; itemToReturn.Product = await _productQueryRepository.GetByIdAsync(itemToReturn.ProductId); return new Response<SaleProducts>(itemToReturn); } else throw new ApplicationException(result.ErrorMessage ?? "There is a problem when saving the product"); }
2. 用ValueTuple返回多值
如果需求简单,直接用元组返回验证状态、数据和错误消息:
// 修改AddProductToSaleAsync的返回类型 public async Task<(SaleProducts? Product, bool IsValid, string? ErrorMsg)> AddProductToSaleAsync(SaleProducts entity) { // 这里写验证逻辑 if (!IsValid(entity)) { return (null, false, "具体的验证失败原因"); } // 执行保存逻辑 var savedProduct = await SaveProduct(entity); return (savedProduct, true, null); }
Handle方法里处理元组:
var (product, isValid, errorMsg) = await _repositoryCommand.AddProductToSaleAsync(newEntity); if(isValid && product != null) { product.Product = await _productQueryRepository.GetByIdAsync(product.ProductId); return new Response<SaleProducts>(product); } else throw new ApplicationException(errorMsg ?? "There is a problem when saving the product");
3. C# 12联合类型(先声明再用)
C# 12支持声明联合类型,先定义一个包含允许返回类型的联合,再用在方法里:
// 定义联合类型 type SaleResult = SaleProducts | string; // 修改AddProductToSaleAsync返回类型 public async Task<SaleResult> AddProductToSaleAsync(SaleProducts entity) { if (!IsValid(entity)) { return "验证不通过的具体原因"; } return await SaveProduct(entity); }
Handle方法里用模式匹配判断返回类型:
var result = await _repositoryCommand.AddProductToSaleAsync(newEntity); if (result is SaleProducts product) { product.Product = await _productQueryRepository.GetByIdAsync(product.ProductId); return new Response<SaleProducts>(product); } else if (result is string errorMsg) { throw new ApplicationException(errorMsg); } else { throw new ApplicationException("Unexpected result type"); }
4. 用第三方联合类型库
还有专门处理联合类型的第三方库,比如OneOf,它封装了联合类型的逻辑,能让代码更简洁,返回类型可以直接写成OneOf<SaleProducts, string>,然后通过库提供的方法匹配不同结果处理。
内容的提问来源于stack exchange,提问作者Rad
相关产品推荐
相关产品推荐

