如何正确结合命令模式、EF Core、类型转换与MS DI实现分发?
解决泛型命令处理器的类型转换问题
你遇到的核心问题是:ICommandHandler<SayHelloToJohnActionData>和ICommandHandler<ActionDataBase>之间不存在继承关系(泛型接口默认是不变的),所以直接强制转换必然失败。下面给两种可行的解决思路:
思路一:引入非泛型基接口
这是最常用的方案,通过非泛型接口统一调用入口:
- 定义非泛型的
ICommandHandler接口,让泛型接口继承它:
public interface ICommandHandler { Task HandleAsync(ActionDataBase actionData); } public interface ICommandHandler<T> : ICommandHandler where T : ActionDataBase { Task HandleAsync(T actionData); }
- 在具体处理器中,显式实现非泛型接口,内部转成具体类型后调用泛型方法:
public class SayHelloToJohnActionHandler : ICommandHandler<SayHelloToJohnActionData> { // 泛型方法:处理具体类型的ActionData public async Task HandleAsync(SayHelloToJohnActionData actionData) { // 你的业务逻辑 Console.WriteLine($"Hello {actionData.TargetName}!"); await Task.CompletedTask; } // 非泛型接口实现:做类型转换,转发到泛型方法 async Task ICommandHandler.HandleAsync(ActionDataBase actionData) { await HandleAsync((SayHelloToJohnActionData)actionData); } }
- 改造Dispatcher的DispatchAsync方法,直接转成非泛型接口调用:
public async Task DispatchAsync(ActionDataBase actionData) { var handlerType = typeof(ICommandHandler<>).MakeGenericType(actionData.GetType()); // 转成非泛型ICommandHandler,避免泛型转换错误 var handler = (ICommandHandler)_provider.GetRequiredService(handlerType); await handler.HandleAsync(actionData); }
思路二:通过反射直接调用泛型方法
如果不想修改现有接口结构,可以用反射调用处理器的HandleAsync方法:
public async Task DispatchAsync(ActionDataBase actionData) { var actionType = actionData.GetType(); var handlerType = typeof(ICommandHandler<>).MakeGenericType(actionType); // 从DI获取处理器实例 var handler = _provider.GetRequiredService(handlerType); // 获取泛型的HandleAsync方法 var handleMethod = handlerType.GetMethod( nameof(ICommandHandler<ActionDataBase>.HandleAsync), new[] { actionType } ); if (handleMethod == null) { throw new InvalidOperationException($"处理器 {handlerType.Name} 未实现HandleAsync方法"); } // 调用异步方法并等待完成 await (Task)handleMethod.Invoke(handler, new object[] { actionData }); }
额外注意事项
- 注册服务时,确保所有
ICommandHandler<T>都被正确注册到DI容器。可以用批量扫描注册简化操作:
services.Scan(scan => scan .FromAssembliesOf(typeof(SayHelloToJohnActionHandler)) .AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<>))) .AsImplementedInterfaces() .WithTransientLifetime());
- 如果你的
HandleAsync方法命名不一致,要注意反射时的方法名匹配,或者用特性标记统一入口。
内容的提问来源于stack exchange,提问作者nktdrkhv
相关产品推荐
相关产品推荐

