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

如何在ServiceCollection中注册非匹配的开放泛型类型

问题场景与解决方案

问题背景

我能正常注册基础开放泛型服务:

services.AddScoped(typeof(IAsyncRepository<>), typeof(AsyncRepository<>));

但面对嵌套泛型的事件处理场景时,常规注册方式失效:

相关类型定义

// 泛型事件接口
public interface IAsyncEvent<in TEvent> where TEvent : class
{
    Task HandleAsync(TEvent eventArg, CancellationToken ct);
}

// 泛型动作类
public class CreateAction<TModel>(TModel model) : ICloneable where TModel : class
{
    public TModel Model { get; } = model;
}

// 事件处理类,实现IAsyncEvent<CreateAction<TModel>>
public class CreateEventAsync<TModel>(IAsyncRepository<TModel> repository) : IAsyncEvent<CreateAction<TModel>> where TModel : class
{
    public async Task HandleAsync(CreateAction<TModel> eventArg, CancellationToken ct)
    {
        await repository.CreateAsync(eventArg.Model, userContext, ct);
    }
}

失败的注册尝试

  1. 运行时错误:
services.AddScoped(
    typeof(IAsyncEvent<>).MakeGenericType(typeof(CreateAction<>)),
    typeof(CreateEventAsync<>)
);
  1. 编译错误:
services.AddScoped(
    typeof(IAsyncEvent<CreateAction<>)),
    typeof(CreateEventAsync<>)
);

需要找到能正确注册该嵌套开放泛型服务的方法,同时支持获取请求的封闭泛型类型来处理额外参数。

可行解决方案

方案1:使用工厂委托注册(推荐)

通过AddScoped的工厂重载,手动解析封闭泛型类型、提取泛型参数并构建实例,这种方式能灵活处理额外参数:

services.AddScoped(typeof(IAsyncEvent<>), (serviceProvider, requestedServiceType) =>
{
    // 提取IAsyncEvent<TEvent>中的TEvent类型(即CreateAction<TModel>)
    var eventType = requestedServiceType.GetGenericArguments()[0];
    // 从CreateAction<TModel>中提取TModel类型
    var modelType = eventType.GetGenericArguments()[0];

    // 构建CreateEventAsync<TModel>的封闭泛型类型
    var handlerConcreteType = typeof(CreateEventAsync<>).MakeGenericType(modelType);

    // 解析构造函数依赖(比如IAsyncRepository<TModel>)
    var repository = serviceProvider.GetRequiredService(
        typeof(IAsyncRepository<>).MakeGenericType(modelType)
    );
    
    // 若有其他参数(如userContext),可在此处补充获取逻辑
    // var userContext = serviceProvider.GetRequiredService<IUserContext>();

    // 创建并返回处理类实例
    return Activator.CreateInstance(handlerConcreteType, repository);
});

方案2:理解原生DI的开放泛型匹配逻辑

原生.NET DI支持嵌套开放泛型注册,但要求服务的泛型参数与实现类的泛型参数直接一一对应。由于CreateEventAsync<TModel>实现的是IAsyncEvent<CreateAction<TModel>>,两者泛型参数是间接映射(TModel → CreateAction<TModel>),直接注册开放泛型会导致DI无法匹配,因此工厂方法是更可靠的选择。

如果你的场景没有额外参数需要处理,也可以考虑自定义扩展方法来封装上述逻辑,但工厂委托已经足够灵活。


内容的提问来源于stack exchange,提问作者Luiz Bicalho

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 20:24:51