我有接口
IOrder<T>
并且 FurnitureOrder<T>
实现了它
我需要注册多个这样的实现
services.AddSingleton(IOrder<Chair>, FurnitureOrder<Chair>())
services.AddSingleton(IOrder<Table>, FurnitureOrder<Table>())
现在我需要检索所有
IOrder
服务和类型(例如椅子、桌子)以对其进行一些背景工作。
我可以使用 GetServices
API 获取它吗?
如果不可能,请建议是否需要更改设计
一种方法是引入一些常见的非通用接口
IOrder
并将所有服务注册为它(类似的框架用于托管服务注册和执行):
interface IOrder
{
}
interface IOrder<T> : IOrder
{
}
services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrder, FurnitureOrder<Chair>>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrder, FurnitureOrder<Table>>());
然后您可以将它们作为
IEnumerable<IOrder>
注入到您的依赖类中,或者使用 IServiceProvider.GetServices<IOrder>()
调用来解析它们。
另请注意,下次注册也应该有效:
services.AddSingleton<IOrder, FurnitureOrder<Chair>>()
services.AddSingleton<IOrder, FurnitureOrder<Table>>()
如果您需要通用注册,您也可以使用类似的方法自动执行非通用注册(在注册所有通用注册之后):
var serviceDescriptors = services
.Where(descriptor => descriptor.ServiceType.IsConstructedGenericType)
.Where(descriptor =>
descriptor.ServiceType.GetGenericTypeDefinition() == typeof(IOrder<>));
foreach (var sd in serviceDescriptors)
{
services.TryAddEnumerable(ServiceDescriptor.Transient(typeof(IOrder),
p => p.GetService(sd.ServiceType))); // or add desciptor creating new based on existing one
}
假设您是指在执行ConfigureServices期间? 你可以这样做:
services.AddSingleton(typeof(IOrder<Chair>), f => new ChairOrder());
var listOf = new List<ServiceDescriptor>();
using var enumerator = services.GetEnumerator();
while (enumerator.MoveNext())
{
var interfaceType = enumerator.Current.ServiceType;
if (!interfaceType.IsGenericType) continue;
if (interfaceType.Name.StartsWith("iorder", System.StringComparison.OrdinalIgnoreCase))
listOf.Add(enumerator.Current);
}
var sp = services.BuildServiceProvider();
foreach(var serviceDescriptor in listOf)
{
var interfaceIWant = serviceDescriptor.ServiceType;
var objectToUse = sp.GetRequiredService(serviceDescriptor.ServiceType);
//TODO:
}
在尝试学习如何装饰/动态代理通用接口的任何注册实现时发现了这个问题。我找到了一个解决方案,将 @t-nielsen 的通用检查和 @guru-stron 的答案结合到
IServiceCollection
的简单扩展方法中(部分也受到 Rey 关于检索通用实现的问答的启发 here )。
扩展方法:
public static IEnumerable<Type?> GetGenericInterfaceImplementationTypes(
this IServiceCollection services,
Type genericInterfaceType)
{
return services
.Where(descriptor =>
Array.Exists(descriptor.ServiceType.GetInterfaces(),
i => i.IsGenericType && (i.GetGenericTypeDefinition() == genericInterfaceType)))
.Select(d => d.ImplementationType);
}
使用示例:
public static IEnumerable<Type?> GetOrderImplementationTypes(this IServiceCollection services)
{
return services.GetGenericInterfaceImplementationTypes(typeof(IOrder<>));
}