You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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 });
    }
}

关键泛型解析知识点

  1. 构造泛型类型:用typeof(泛型接口模板<>).MakeGenericType(类型参数数组)来创建具体的泛型类型。比如typeof(IQueryHandler<,>)是泛型模板,传入typeof(TQuery)和typeof(TResult)就得到了IQueryHandler<TQuery, TResult>的具体类型。
  2. 获取运行时类型:通过query.GetType()拿到实例的具体类型,而不是编译时的IQuery<TResult>接口类型。
  3. 反射调用方法:当编译时无法确定泛型类型时,用GetMethod找到方法,再用Invoke调用。

关于IQueryHandler的小修正

你原定义里的Handle方法带了<TResult>泛型参数,这会导致和接口本身的TResult冲突,而且完全没必要——因为TQuery已经被约束为IQuery<TResult>,所以Handler的Handle方法直接返回接口定义的TResult即可,修正后的接口才符合CQRS Query Handler的常规设计。

内容的提问来源于stack exchange,提问作者David Keaveny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:17:47