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

泛型接口派生类DI注入问题:IModelProcessor实现无法注入工厂

问题原因

你注册的IModelProcessor<ConcreteOne>等具体泛型服务,与工厂依赖的IModelProcessor<MyAbstractClass>在.NET泛型系统中是完全独立的类型——默认情况下,泛型接口不支持隐式类型转换,因此DI容器无法将前者识别为后者的实现,导致注入时找不到匹配的服务,最终集合为null。

解决方案

方案1:显式注册为基泛型接口

在注册每个处理器时,额外将其注册为IModelProcessor<MyAbstractClass>类型,让DI容器将这些实例纳入目标集合:

// 注册具体泛型接口
builder.Services.AddScoped<IModelProcessor<ConcreteOne>, ConcreteOneProcessor>();
// 同时注册为基泛型接口
builder.Services.AddScoped<IModelProcessor<MyAbstractClass>>(sp => 
    sp.GetRequiredService<IModelProcessor<ConcreteOne>>());

builder.Services.AddScoped<IModelProcessor<ConcreteTwo>, ConcreteTwoProcessor>();
builder.Services.AddScoped<IModelProcessor<MyAbstractClass>>(sp => 
    sp.GetRequiredService<IModelProcessor<ConcreteTwo>>());

builder.Services.AddScoped<IModelProcessor<ConcreteThree>, ConcreteThreeProcessor>();
builder.Services.AddScoped<IModelProcessor<MyAbstractClass>>(sp => 
    sp.GetRequiredService<IModelProcessor<ConcreteThree>>());

方案2:将接口改为逆变泛型

如果你的业务逻辑允许(即泛型参数仅用作方法输入,无返回值场景),可以给IModelProcessor添加in关键字标记逆变:

public interface IModelProcessor<in S>
    where S : MyAbstractClass
{
    void ProcessModel(S myAbstractClass);
}

逆变允许IModelProcessor<ConcreteOne>隐式转换为IModelProcessor<MyAbstractClass>,此时你原来的注册方式即可生效,DI容器会自动将所有具体处理器注入到IEnumerable<IModelProcessor<MyAbstractClass>>集合中。

方案3:基于类型字典的工厂模式(更灵活)

若上述方案不适用,可修改工厂逻辑,通过反射识别处理器对应的模型类型,维护一个类型映射字典:

修改工厂类

public class ModelProcessorFactory : IModelProcessorFactory
{
    private readonly Dictionary<Type, IModelProcessor<MyAbstractClass>> _processorLookup;

    public ModelProcessorFactory(IEnumerable<object> allProcessors)
    {
        _processorLookup = allProcessors
            .OfType<IModelProcessor<MyAbstractClass>>()
            .ToDictionary(processor => 
                // 提取处理器对应的泛型模型类型
                processor.GetType()
                    .GetInterfaces()
                    .First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IModelProcessor<>))
                    .GetGenericArguments()[0]);
    }

    // 新增方法:根据模型类型获取对应处理器
    public IModelProcessor<MyAbstractClass> GetProcessorForModel(Type modelType)
    {
        _processorLookup.TryGetValue(modelType, out var processor);
        return processor;
    }
}

保持原有注册方式

builder.Services.AddScoped<IModelProcessor<ConcreteOne>, ConcreteOneProcessor>();
builder.Services.AddScoped<IModelProcessor<ConcreteTwo>, ConcreteTwoProcessor>();
builder.Services.AddScoped<IModelProcessor<ConcreteThree>, ConcreteThreeProcessor>();
builder.Services.AddScoped<IModelProcessorFactory, ModelProcessorFactory>();

这种方式无需修改泛型接口的兼容性,同时支持根据模型类型动态获取处理器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 01:13:59