.NET Core注册泛型IOrder<T>实现后能否通过GetServices获取所有服务
问题解答
能否直接通过GetServices API实现?
直接调用GetServices(typeof(IOrder<>))无法获得你注册的所有IOrder<Chair>、IOrder<Table>实例,原因是你注册的是闭合构造泛型类型(已经指定了具体泛型参数的泛型类型),而IOrder<>是开放泛型定义,二者在DI容器中属于不同的服务类型,默认没有关联,因此无法直接通过开放泛型定义批量获取所有闭合泛型实现。
如果使用支持开放泛型批量解析的第三方DI容器(如Autofac),可以直接注册开放泛型services.AddSingleton(typeof(IOrder<>), typeof(FurnitureOrder<>)),之后直接解析IEnumerable<IOrder<>>即可获取所有泛型实现,但.NET官方自带DI不支持该特性。
实现方案
方案1:无需修改现有接口定义,通过反射遍历获取
如果不想调整现有接口结构,可以通过遍历所有需要的泛型参数类型,动态构造闭合泛型类型后逐个从容器获取实例:
- 首先定义标记接口(可选,用于快速筛选所有可用的泛型参数类型,也可以手动维护T类型列表省略该步骤):
// 所有IOrder<T>的T参数都实现该标记接口 public interface IOrderItem { } public class Chair : IOrderItem { } public class Table : IOrderItem { }
- 后台服务中批量获取实例:
public class OrderBackgroundService : BackgroundService { private readonly IServiceProvider _serviceProvider; public OrderBackgroundService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // 扫描程序集获取所有实现IOrderItem的类型 var orderItemTypes = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes()) .Where(t => typeof(IOrderItem).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); foreach (var itemType in orderItemTypes) { // 动态构造闭合泛型类型 IOrder<ItemType> var closedOrderType = typeof(IOrder<>).MakeGenericType(itemType); // 从容器获取对应服务 var orderService = _serviceProvider.GetService(closedOrderType); if (orderService != null) { // 这里可以通过反射调用orderService的方法,或者转换为动态类型执行 await (Task)closedOrderType.GetMethod("你的业务方法名")?.Invoke(orderService, new object[] { stoppingToken }); } } } }
方案2:调整接口设计,新增非泛型基接口(更推荐)
该方案复杂度更低,运行效率更高,也不需要依赖反射:
- 新增非泛型基接口:
public interface IOrder { // 暴露对应的泛型参数类型 Type OrderItemType { get; } // 统一的任务执行入口 Task ExecuteAsync(CancellationToken cancellationToken); } // 原泛型接口继承非泛型基接口 public interface IOrder<T> : IOrder { } // 实现类中实现基接口属性 public class FurnitureOrder<T> : IOrder<T> { public Type OrderItemType => typeof(T); public Task ExecuteAsync(CancellationToken cancellationToken) { // 你的业务逻辑 return Task.CompletedTask; } }
- 注册逻辑无需修改,直接批量获取所有实例:
var allOrderServices = serviceProvider.GetServices<IOrder>(); foreach (var order in allOrderServices) { // 直接获取对应的泛型参数类型 var itemType = order.OrderItemType; // 执行任务 await order.ExecuteAsync(stoppingToken); }
内容的提问来源于stack exchange,提问作者swathi
相关产品推荐
相关产品推荐

