如何在大型代码库中通过依赖注入传递依赖项
解决依赖注入中内层类实例化的问题
你遇到的问题是典型的DI示例只展示顶层注入,但实际业务中内层类依赖处理的误区——手动传递依赖或直接暴露ServiceProvider都违背了DI的设计初衷,这里给出几种符合DI原则的解决方案:
方案1:固定依赖直接构造注入
如果MyNestedClass是MyClass的固定依赖(每次执行Run都需要,或生命周期与MyClass绑定),直接将MyNestedClass注册到容器,并通过MyClass的构造函数注入,完全避免手动实例化:
class Program { static void Main(string[] args) { var services = new ServiceCollection(); services.AddLogging(configure => configure.AddSerilog()); // 注册所有需要的服务类型 services.AddTransient<MyClass>(); services.AddTransient<MyNestedClass>(); var serviceProvider = services.BuildServiceProvider(); var myClass = serviceProvider.GetRequiredService<MyClass>(); myClass.Run(); } } class MyClass { private readonly ILogger<MyClass> _logger; private readonly MyNestedClass _nestedClass; // 构造函数注入MyNestedClass,依赖由容器自动解析 public MyClass(ILogger<MyClass> logger, MyNestedClass nestedClass) { _logger = logger; _nestedClass = nestedClass; } public void Run() { _nestedClass.DoSomeWork(); } } class MyNestedClass { private readonly ILogger<MyNestedClass> _logger; public MyNestedClass(ILogger<MyNestedClass> logger) { _logger = logger; } public void DoSomeWork() { _logger.LogInformation("执行嵌套类工作"); } }
方案2:动态实例化用工厂封装
如果MyNestedClass需要在运行时动态创建(比如每次Run生成新实例,或需要传入运行时参数),不要直接传递ServiceProvider,而是用工厂模式封装容器的使用:
简单动态实例化(无额外参数)
利用.NET DI容器自动支持Func<T>的特性,直接注入工厂委托:
class MyClass { private readonly ILogger<MyClass> _logger; private readonly Func<MyNestedClass> _nestedClassFactory; // 注入Func<MyNestedClass>作为工厂,容器自动解析 public MyClass(ILogger<MyClass> logger, Func<MyNestedClass> nestedClassFactory) { _logger = logger; _nestedClassFactory = nestedClassFactory; } public void Run() { // 动态创建新的MyNestedClass实例 var nestedClass = _nestedClassFactory(); nestedClass.DoSomeWork(); } }
容器注册时无需额外配置,只要MyNestedClass已注册即可。
带运行时参数的动态实例化
如果需要给MyNestedClass传递运行时才确定的参数,定义专门的工厂接口封装ActivatorUtilities的使用:
// 定义工厂接口 public interface IMyNestedClassFactory { MyNestedClass Create(string runtimeParameter); } // 工厂实现类,仅在这里依赖IServiceProvider public class MyNestedClassFactory : IMyNestedClassFactory { private readonly IServiceProvider _serviceProvider; public MyNestedClassFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public MyNestedClass Create(string runtimeParameter) { // 结合容器和运行时参数创建实例 return ActivatorUtilities.CreateInstance<MyNestedClass>(_serviceProvider, runtimeParameter); } }
注册工厂到容器:
services.AddTransient<IMyNestedClassFactory, MyNestedClassFactory>();
然后MyClass注入工厂并使用:
class MyClass { private readonly ILogger<MyClass> _logger; private readonly IMyNestedClassFactory _nestedClassFactory; public MyClass(ILogger<MyClass> logger, IMyNestedClassFactory nestedClassFactory) { _logger = logger; _nestedClassFactory = nestedClassFactory; } public void Run() { var runtimeParam = "运行时生成的参数"; var nestedClass = _nestedClassFactory.Create(runtimeParam); nestedClass.DoSomeWork(); } }
为什么不要直接传递ServiceProvider
直接传递ServiceProvider属于服务定位器模式,会带来以下问题:
- 类与DI容器耦合,难以替换容器或进行单元测试
- 隐藏了类的真实依赖,代码可读性和可维护性下降
- 违背依赖倒置原则,类主动获取依赖而非被动接收
内容的提问来源于stack exchange,提问作者user21141188
相关产品推荐
相关产品推荐

