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

如何在IServiceCollection的AddScoped中使用泛型接口并注入所有相关Builder?

解决泛型Builder类的DI注册与批量注入问题

1. 让泛型接口支持协变

默认情况下,泛型接口IBuilder<T>是不变的,这意味着IBuilder<SquareFeetRow>无法被当作IBuilder<IOrganizationNames>使用。要解决这个问题,需要给泛型参数添加out关键字开启协变:

public interface IBuilder<out T> where T : IOrganizationNames { ... }

协变允许将派生类型的泛型接口实例赋值给基类型的泛型接口变量,正好匹配你需要将所有IBuilder<T>(T实现IOrganizationNames)统一注入为IBuilder<IOrganizationNames>的场景。

2. 自动批量注册所有Builder类

不用逐个手动注册每个Builder,通过反射扫描程序集中符合约定的类型,自动完成注册:

编写扩展方法

using System.Reflection;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddAllBuilders(this IServiceCollection services, Assembly targetAssembly)
    {
        // 筛选所有符合条件的Builder类:非抽象、非泛型、实现了IBuilder<T>且T继承自IOrganizationNames
        var builderTypes = targetAssembly.GetTypes()
            .Where(type => !type.IsAbstract 
                           && !type.IsGenericType
                           && type.GetInterfaces().Any(@interface =>
                               @interface.IsGenericType
                               && @interface.GetGenericTypeDefinition() == typeof(IBuilder<>))
                               && typeof(IOrganizationNames).IsAssignableFrom(@interface.GetGenericArguments()[0])));

        foreach (var builderType in builderTypes)
        {
            // 获取该Builder对应的泛型接口(比如IBuilder<SquareFeetRow>)
            var genericInterface = builderType.GetInterfaces()
                .First(@interface => @interface.IsGenericType && @interface.GetGenericTypeDefinition() == typeof(IBuilder<>));

            // 1. 注册为具体泛型接口(支持直接注入IBuilder<SquareFeetRow>)
            services.AddScoped(genericInterface, builderType);
            // 2. 注册为IBuilder<IOrganizationNames>(支持批量注入)
            services.AddScoped(typeof(IBuilder<IOrganizationNames>), provider =>
                provider.GetRequiredService(genericInterface));
        }

        return services;
    }
}

在Program.cs中调用扩展方法

// 传入包含Builder类的程序集(示例为当前执行程序集)
builder.Services.AddAllBuilders(Assembly.GetExecutingAssembly());

3. 验证注入效果

现在你的MyService中注入IEnumerable<IBuilder<IOrganizationNames>>就能正常获取所有Builder实例了:

public sealed class MyService
{
    public MyService(IEnumerable<IBuilder<IOrganizationNames>> builders)
    {
        // builders集合会包含所有注册的Builder实例
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 04:17:20