You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在大型代码库中通过依赖注入传递依赖项

解决依赖注入中内层类实例化的问题

你遇到的问题是典型的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:22:42