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

键控依赖注入:如何获取所有已注册对象及其键?

自动获取所有键控IFoo实例及其键的解决方案

方案一:在注册IFooController时直接筛选服务描述符

保持IFoo的键控注册逻辑不变:

builder.Services.AddKeyedSingleton<IFoo, Foo>("Foo");
builder.Services.AddKeyedSingleton<IFoo, Bar>("Bar");

修改IFooController的注册代码,从服务描述符集合中自动提取所有IFoo的键控服务:

builder.Services.AddScoped<IFooController>(provider =>
{
    // 筛选所有注册的IFoo键控服务描述符
    var fooServiceDescriptors = builder.Services
        .Where(sd => sd.ServiceType == typeof(IFoo) && sd.IsKeyedService)
        .ToList();

    // 遍历描述符,获取对应键与实例
    var fooInstances = fooServiceDescriptors
        .Select(sd => (
            Key: sd.ServiceKey?.ToString() ?? string.Empty,
            Foo: provider.GetRequiredKeyedService<IFoo>(sd.ServiceKey)
        ))
        .ToList();

    return ActivatorUtilities.CreateInstance<FooBarController>(provider, fooInstances);
});

说明

  • 借助builder.Services(服务描述符集合)自动筛选目标服务,无需手动逐个指定键。
  • 后续新增IFoo的键控注册时,无需修改这段代码,新实例会自动被纳入集合。
  • 针对ServiceKey可能为null的情况,用?? string.Empty做兜底处理,可根据实际需求调整。

方案二:自定义集合服务实现构造注入

如果希望FooBarController通过标准构造注入获取实例集合,可先注册一个专门的集合服务:

// 注册收集所有IFoo键控实例的集合服务
builder.Services.AddSingleton<IEnumerable<(string Key, IFoo Foo)>>(provider =>
{
    var serviceCollection = provider.GetRequiredService<IServiceCollection>();
    var fooDescriptors = serviceCollection
        .Where(sd => sd.ServiceType == typeof(IFoo) && sd.IsKeyedService);

    return fooDescriptors.Select(sd => (
        sd.ServiceKey?.ToString() ?? string.Empty,
        provider.GetRequiredKeyedService<IFoo>(sd.ServiceKey)
    ));
});

// 直接注册IFooController,无需手动创建实例
builder.Services.AddScoped<IFooController, FooBarController>();

修改FooBarController的构造函数,直接注入集合:

public class FooBarController : IFooController
{
    private readonly IEnumerable<(string Key, IFoo Foo)> _fooInstances;

    public FooBarController(IEnumerable<(string Key, IFoo Foo)> fooInstances)
    {
        _fooInstances = fooInstances;
    }

    // 实现IFooController的操作方法,遍历_fooInstances处理每个IFoo实例
}

说明

  • 这种方式更符合依赖注入的设计惯例,控制器无需通过ActivatorUtilities手动实例化。
  • 集合服务会在首次被注入时,自动收集当前所有注册的IFoo键控实例。

注意事项

  • 若存在非键控的IFoo注册(未使用AddKeyed*方法注册的实例),可移除sd.IsKeyedService筛选条件将其纳入,同时处理ServiceKey为null的场景。
  • 如果ServiceKey是复杂类型而非字符串,需替换ToString()逻辑为适合的键标识方式(比如自定义类型的专属属性)。
  • 该方案适用于.NET 7及以上版本(键控服务从.NET 7开始正式支持)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:51:13