.NET依赖注入:非容器创建类如何获取服务?
.NET中未注册DI容器的类获取服务的最佳实践
在.NET里,如果类没被DI容器实例化、无法通过构造函数注入服务时,不用硬传容器引用,有几种更合理的方案,同时要注意避免反模式:
一、优先规避全局容器的反模式
直接用全局容器(比如静态类持有IServiceProvider)会导致代码耦合度高、难以测试,属于DI的反模式,除非万不得已,不要优先采用。
二、可行的实现方式
1. 局部传递具体服务或IServiceProvider
在创建未注册类的调用方(比如已注册到DI的类、工厂类)中,从DI获取所需的具体服务或IServiceProvider,再传递给未注册类的构造函数或方法:
// 已注册到DI的调用方类 public class RegisteredService { private readonly IMyDependency _dependency; public RegisteredService(IMyDependency dependency) { _dependency = dependency; } public void Execute() { // 直接传递具体服务,而非整个容器,依赖关系更清晰 var unregisteredInstance = new UnregisteredClass(_dependency); unregisteredInstance.DoWork(); } }
2. 用工厂模式封装实例化逻辑
创建专门的工厂类并注册到DI,由工厂负责实例化未注册类并注入所需服务,上层代码只依赖工厂抽象,不直接接触容器:
// 抽象工厂接口 public interface IUnregisteredClassFactory { UnregisteredClass Create(); } // 工厂实现(注册到DI) public class UnregisteredClassFactory : IUnregisteredClassFactory { private readonly IMyDependency _dependency; private readonly IAnotherDependency _anotherDependency; // 工厂通过构造函数注入所需服务 public UnregisteredClassFactory(IMyDependency dependency, IAnotherDependency anotherDependency) { _dependency = dependency; _anotherDependency = anotherDependency; } public UnregisteredClass Create() { return new UnregisteredClass(_dependency, _anotherDependency); } } // 使用工厂的业务类 public class BusinessService { private readonly IUnregisteredClassFactory _factory; public BusinessService(IUnregisteredClassFactory factory) { _factory = factory; } public void RunTask() { var instance = _factory.Create(); instance.Process(); } }
3. 静态服务定位器(谨慎使用)
如果以上方案都不适用,再考虑静态定位器,这是最后手段:
public static class ServiceLocator { private static IServiceProvider _serviceProvider; public static void Initialize(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public static T GetRequiredService<T>() { return _serviceProvider.GetRequiredService<T>(); } } // 在Program.cs中初始化 var app = builder.Build(); ServiceLocator.Initialize(app.Services); // 未注册类中使用 public class UnregisteredClass { public void DoWork() { var dependency = ServiceLocator.GetRequiredService<IMyDependency>(); // 执行业务逻辑 } }
注意:这种方式会让代码难以单元测试、依赖关系不透明,仅适合在工具类、基础设施层等非业务逻辑场景使用。
三、大型复杂应用的最佳实践
- 尽量将所有业务类注册到DI:除非是动态生成、第三方库类等特殊情况,否则优先通过构造函数注入保持依赖清晰。
- 限制服务定位器的使用范围:如果必须用,只在特定层(如基础设施层)使用,禁止在业务逻辑层滥用。
- 使用泛型抽象工厂:针对需要批量创建的类,定义泛型工厂接口,减少重复代码,同时保持依赖抽象。
- 避免传递整个容器:尽量传递具体的服务实例,而非
IServiceProvider,让类的依赖关系更明确,降低耦合。
内容的提问来源于stack exchange,提问作者whatever
相关产品推荐
相关产品推荐

