从 IServiceProvider 获取给定类型的所有实现,无论它们是否有键控

问题描述 投票:0回答:2

为什么这不是重复的

不要与“

如何从键控服务获取键和类型”混淆,该问题仅讨论如何获取所有键控类型,也许这是答案的一部分,但不讨论非键控类型以及如何将它们考虑在内,因为有人花了很长时间在谷歌上搜索这个问题,该问题的答案并没有回答这里的问题,并且出于可搜索性的目的,该问题比这个要具体得多,这是一个更高级别的“所有实现”不仅仅是其中所要求的“关键实现”。

实际问题

自 .net 8 以来,微软似乎添加了拥有密钥服务的功能,这看起来很棒,但我注意到调用

serviceProvider.GetServices(typeof(SomeInterface));

 不会返回也具有密钥信息的实例。

例如:

var collection = new ServiceCollection(); collection.AddKeyedSingleton<ITestInterface, TestClass1>("test1"); collection.AddKeyedSingleton<ITestInterface, TestClass2>("test2"); collection.AddSingleton<ITestInterface, TestClass3>(); var serviceProvider = collection.BuildServiceProvider(); var implementations = serviceProvider.GetServices<ITestInterface>(); Assert.NotNull(implementations); Assert.NotEmpty(implementations); // Expecting TestClass1, TestClass2, TestClass3 Assert.True(implementations.Count() == 3); // Actually just TestClass3
我不确定上述测试的预期行为,我认为它应该通过并返回给定类型的所有绑定。那么就提出了如何从

serviceProvider

获得预期结果的问题。

我想也许我需要使用

serviceProvider.GetKeyedServices<ITestInterface>()

,但不幸的是,这需要您提供一个密钥,在这种情况下,我们想忽略密钥并只获取给定类型的所有实现。

那么任何人都可以建议如何获得预期的行为吗?即使它需要两个服务提供商方法之间的联合。

c# .net dependency-injection .net-8.0 servicecollection
2个回答
4
投票
您所经历的行为是设计使然,尽管 Microsoft 很可能选择将密钥服务作为集合的一部分的行为。但默认情况下,它们不是。

虽然

我的这个答案解释了如何将所有密钥注册解析为IDictionary<TKey, TService>

,但这并不能让您获得您希望看到的行为。

但是,可以使用自定义扩展方法来实现此行为:

public static void AddBothKeyedAndDefaultSingleton<TService, TImplementation>( IServiceCollection services, string key) where TService : class where TImplementation : class, TService { services.AddKeyedSingleton<TService, TImplementation>(key); services.AddSingleton(sp => sp.GetRequiredKeyedService<TService>(key)); }
如果您使用此扩展方法运行测试,您将获得预期的输出:

var collection = new ServiceCollection(); collection.AddBothKeyedAndDefaultSingleton<ITestInterface, TestClass1>("test1"); collection.AddBothKeyedAndDefaultSingleton<ITestInterface, TestClass2>("test2"); collection.AddSingleton<ITestInterface, TestClass3>(); var serviceProvider = collection.BuildServiceProvider(); var implementations = serviceProvider.GetServices<ITestInterface>(); Assert.True(implementations.Count() == 3);
您可能会想迭代整个 

IServiceCollection

 并为每个键控注册添加额外的注册,从而使其成为全局行为更改,但这将是一个严重的错误。您正在使用的其他可重用库和框架组件(或将来要安装的更新)很可能取决于当前的行为。


0
投票
有一个鲜为人知的技巧可以使用库提供的特殊静态密钥来解决此问题:

var implementations = serviceProvider.GetKeyedServices<ITestInterface>(KeyedService.AnyKey);
此方法存在一个错误,已在 .NET 9 中修复。因此请确保至少升级到 .NET 9 或获取相应的 v9.0.0 NuGet 包 (

Microsoft.Extensions.DependencyInjection.Abstractions

)。

© www.soinside.com 2019 - 2024. All rights reserved.