.Net Core依赖注入:如何根据服务类型(接口)获取已注册实现类型
在.NET Core中根据服务接口获取已注册实现类型的实现方法
完全可以实现,全程不需要创建任何服务实例,核心是直接读取DI流程中存储的注册元数据
基本原理
我们平时在Startup.ConfigureServices中写的每一条依赖注册逻辑,最终都会被封装成一个ServiceDescriptor对象存在IServiceCollection集合里,这个对象自带三个核心属性:
- 注册的服务标识(也就是我们传入的接口/抽象类类型,对应
ServiceType属性) - 对应的具体实现类型(对应
ImplementationType属性) - 服务声明的生命周期(Transient/Scoped/Singleton)
比如你示例中的services.AddTransient<IBaseRepository, BaseRepository>(),本质就是生成了一条ServiceDescriptor记录,其中ServiceType就是typeof(IBaseRepository),ImplementationType就是typeof(BaseRepository),只要读取这条记录就能直接拿到目标实现类型,根本不需要实际把服务实例解析出来。
具体实现代码
场景1:还在ConfigureServices方法内做查询
这个阶段服务集合还没被构建成最终的容器,直接遍历集合做匹配就行,不会触发任何服务的实例化逻辑:
/// <summary> /// 从服务注册集合中匹配指定服务类型对应的实现类型 /// </summary> /// <param name="services">依赖注册集合</param> /// <param name="serviceType">要查询的服务接口/抽象类型</param> /// <returns>匹配到的实现类型,无匹配时返回null</returns> public static Type GetImplementationType(IServiceCollection services, Type serviceType) { return services // 筛选匹配目标服务类型、且有明确实现类型的注册条目 .Where(descriptor => descriptor.ServiceType == serviceType && descriptor.ImplementationType != null ) // 取第一个匹配的实现类型,如果需要拿该服务的所有注册实现,直接把结果收集为List即可 .Select(descriptor => descriptor.ImplementationType) .FirstOrDefault(); }
调用的时候直接传入接口类型就能拿到结果:
// 传入IBaseRepository类型,直接得到typeof(BaseRepository) var matchedImplType = GetImplementationType(services, typeof(IBaseRepository));
场景2:应用已经启动完成(已构建IServiceProvider)的运行时查询
如果已经完成启动、拿到了根服务提供者,在.NET 8及以上版本中,容器本身就暴露了所有注册条目的查询能力,不需要手动写反射:
// 从根容器中直接获取所有已注册的ServiceDescriptor集合 var allRegisteredDescriptors = rootServiceProvider.GetRequiredService<IEnumerable<ServiceDescriptor>>(); // 后续的匹配查询逻辑和之前的写法完全一致
需要注意的边界情况
- 工厂注册的服务拿不到固定实现类型:如果注册的时候是用委托工厂的方式写的,比如
services.AddTransient<IBaseRepository>(sp => new BaseRepository()),对应的ServiceDescriptor上的ImplementationType属性是null,没法通过上面的方法直接拿到固定的实现类型。 - 同一服务可能注册多个实现:上面的查询逻辑默认返回注册顺序中排在最前面的条目,如果需要拿到某一个接口对应的所有实现,直接把所有匹配的
ImplementationType收集起来就行。 - 不要走解析实例反推类型的弯路:很多人第一反应是调用
provider.GetService(targetType)拿到服务实例,再通过instance.GetType()拿实现类型,但这种方式会顺着依赖链把所有关联的服务都实例化一遍,很容易触发非预期的副作用,完全违背了“只取类型、不生成实例”的初衷。
内容的提问来源于stack exchange,提问作者wk-done
相关产品推荐
相关产品推荐

