C#异步责任链模式的异常处理问题:如何在注册类中捕获处理器抛出的异常
C#异步责任链模式的异常处理问题:如何在注册类中捕获处理器抛出的异常
嘿,我来帮你搞定这个异常捕获的问题!你现在遇到的情况,主要是因为异步责任链里的异步操作没有被正确等待,还有一个小笔误导致的问题,咱们一步步来解决:
问题根源分析
- 异步调用未等待:你的基类
Handler<T>的Handle方法里,调用Next?.Handle(request)时没有用await。因为Handle是async Task方法,不等待的话,这个异步操作会变成“执行后不管”的状态,抛出的异常会在后台线程中逃逸,根本传不到Register方法的try/catch块里。 - 子类中的笔误:
OnlyAdultValidationHandler里有一行多余的throw new Exception();,这会直接抛出异常,而且同样因为上面的等待问题,无法被捕获。
解决方案步骤
第一步:修复基类的异步等待逻辑
修改基类Handler<T>的Handle方法,给下一个处理器的调用加上await,确保异步操作的异常能正常传播:
using System.Threading.Tasks; namespace Chain.Of.Responsibility.Example.Chain.Pattern { public abstract class Handler<T> : IHandler<T> { private IHandler<T> Next { get; set; } public virtual async Task Handle(T request) { // 必须等待下一个处理器的异步操作,否则异常会逃逸 await Next?.Handle(request); } public IHandler<T> SetNext(IHandler<T> next) { Next = next; return Next; } } // 确保IHandler<T>接口定义正确 public interface IHandler<T> { Task Handle(T request); } }
第二步:修复子类中的调用和笔误
每个子类在调用base.Handle(user)时也需要加await,同时删掉OnlyAdultValidationHandler里多余的throw语句:
修改后的UsernameRequiredValidationHandler
using System; using System.Threading.Tasks; namespace Chain.Of.Responsibility.Example.Chain.Pattern { public class UsernameRequiredValidationHandler : Handler<User> { public override async Task Handle(User user) { if (string.IsNullOrWhiteSpace(user.Username)) { throw new Exception("Username is required."); } // 等待基类的异步处理(即下一个处理器) await base.Handle(user); } } }
修改后的PasswordRequiredValidationHandler
using System; using System.Threading.Tasks; namespace Chain.Of.Responsibility.Example.Chain.Pattern { public class PasswordRequiredValidationHandler : Handler<User> { public override async Task Handle(User user) { if (string.IsNullOrWhiteSpace(user.Password)) { throw new Exception("Password is required."); } await base.Handle(user); } } }
修改后的OnlyAdultValidationHandler
using System; using System.Threading.Tasks; namespace Chain.Of.Responsibility.Example.Chain.Pattern { public class OnlyAdultValidationHandler : Handler<User> { public override async Task Handle(User user) { // 删掉多余的throw语句 if (user.BirthDate.Year > DateTime.Now.Year - 18) { throw new Exception("Age under 18 is not allowed."); } await base.Handle(user); } } }
第三步:验证注册类的异常捕获
你的ChainPatternRegistrationProcessor代码不需要修改,因为已经用了await handler.Handle(user);,现在所有处理器抛出的异常都会被正确传播到try/catch块中,你会在控制台看到异常信息,并且可以正常处理。
关键总结
- 所有
async Task方法的调用都必须用await,否则异常会逃逸到后台线程,无法被上层捕获。 - 异步责任链的每个节点都要确保等待下一个节点的异步操作,这样异常才能沿着链条向上传播。
- 检查代码中的笔误,避免不必要的异常抛出。
备注:内容来源于stack exchange,提问作者Masoud H
相关产品推荐
相关产品推荐

