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

.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 19:27:22