如何在C#中解析泛型类型?附相关接口与Dispatcher实现场景
嘿,我来帮你搞定这个泛型解析的问题!首先先把你给出的代码清晰列出来,方便我们一步步梳理:
你定义的泛型接口
public interface IQuery<out TResult> { } // 先提个小修正:原定义里的Handle方法泛型参数有点问题,我后面会说明 public interface IQueryHandler<in TQuery, out TResult> where TQuery : IQuery<TResult> { // 原代码是 TResult Handle<TResult>(TQuery query); 这里的<TResult>是多余的,会和接口的TResult冲突 TResult Handle(TQuery query); } public interface IDispatcher { TResult Query<TQuery, TResult>(TQuery query) where TQuery : IQuery<TResult>; TResult Query<TResult>(IQuery<TResult> query); }
核心问题:Dispatcher里如何解析泛型类型
你的Dispatcher需要根据传入的Query实例,找到对应的IQueryHandler<TQuery, TResult>并调用它的Handle方法。这里的泛型解析核心是通过反射获取运行时的泛型类型参数,构造对应的Handler类型,再结合依赖注入(或者手动类型查找)获取Handler实例。
下面是完整的Dispatcher实现,我会逐段解释泛型解析的逻辑:
public class Dispatcher : IDispatcher { // 依赖注入容器,用来获取对应的Handler实例 private readonly IServiceProvider _serviceProvider; public Dispatcher(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } // 第一个Query方法:编译时就知道TQuery和TResult,解析很直接 public TResult Query<TQuery, TResult>(TQuery query) where TQuery : IQuery<TResult> { // 1. 构造对应的Handler泛型类型:IQueryHandler<TQuery, TResult> var handlerType = typeof(IQueryHandler<,>).MakeGenericType(typeof(TQuery), typeof(TResult)); // 2. 从容器中获取Handler实例 var handler = (IQueryHandler<TQuery, TResult>)_serviceProvider.GetService(handlerType); if (handler == null) { throw new InvalidOperationException($"找不到处理{typeof(TQuery).Name}的Handler"); } // 3. 直接调用Handle方法(编译时类型明确,不需要反射) return handler.Handle(query); } // 第二个Query方法:只知道TResult和IQuery<TResult>实例,需要解析具体的TQuery类型 public TResult Query<TResult>(IQuery<TResult> query) { // 1. 获取Query的具体运行时类型(比如你传入的是GetUserQuery实例,这里得到typeof(GetUserQuery)) var queryConcreteType = query.GetType(); // 2. 构造对应的Handler泛型类型:IQueryHandler<具体Query类型, TResult> var handlerType = typeof(IQueryHandler<,>).MakeGenericType(queryConcreteType, typeof(TResult)); // 3. 从容器中获取Handler实例 var handler = _serviceProvider.GetService(handlerType); if (handler == null) { throw new InvalidOperationException($"找不到处理{queryConcreteType.Name}的Handler"); } // 4. 反射调用Handle方法(因为编译时不知道具体的TQuery类型,无法强转后直接调用) var handleMethod = handlerType.GetMethod(nameof(IQueryHandler<object, object>.Handle)); return (TResult)handleMethod.Invoke(handler, new object[] { query }); } }
关键泛型解析知识点
- 构造泛型类型:用
typeof(泛型接口模板<>).MakeGenericType(类型参数数组)来创建具体的泛型类型。比如typeof(IQueryHandler<,>)是泛型模板,传入typeof(TQuery)和typeof(TResult)就得到了IQueryHandler<TQuery, TResult>的具体类型。 - 获取运行时类型:通过
query.GetType()拿到实例的具体类型,而不是编译时的IQuery<TResult>接口类型。 - 反射调用方法:当编译时无法确定泛型类型时,用
GetMethod找到方法,再用Invoke调用。
关于IQueryHandler的小修正
你原定义里的Handle方法带了<TResult>泛型参数,这会导致和接口本身的TResult冲突,而且完全没必要——因为TQuery已经被约束为IQuery<TResult>,所以Handler的Handle方法直接返回接口定义的TResult即可,修正后的接口才符合CQRS Query Handler的常规设计。
内容的提问来源于stack exchange,提问作者David Keaveny
相关产品推荐
相关产品推荐

