键控依赖注入:如何获取所有已注册对象及其键?
自动获取所有键控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
相关产品推荐
相关产品推荐

