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

.NET Core依赖注入:运行时循环场景下正确解析服务的方案选择

方案优先级排序及原因

优先选择方案2,特殊场景可选方案1,完全舍弃方案3

  • 方案3直接排除:
    手动new ClassA会完全丧失DI容器的依赖管理能力,后续ClassA新增依赖时所有创建点都要同步修改,维护成本极高。如果ClassA有ILogger这类容器托管的依赖,你还需要手动传递,等于完全背离了DI的设计初衷,只有当ClassA无任何外部依赖的极端场景下才可能考虑,否则完全不推荐。
  • 方案1的问题说明:
    直接在业务代码中使用IServiceScopeFactory + 服务定位器的写法,会导致你的业务代码和DI容器强耦合,且类的依赖关系不透明:从构造函数只能看到ClassA依赖IServiceScopeFactory,无法得知它实际还依赖IClassA,依赖错误只能在运行期暴露,单元测试时还需要模拟整套DI容器相关的接口,测试成本很高。
    微软官方文档提到该用法是作为底层能力说明,并非推荐在业务代码中直接使用,这也是它被很多人视为反模式的核心原因。
  • 方案2的优势:
    工厂封装的方式把DI相关的逻辑完全隔离在工厂实现类中,业务代码只依赖抽象的IClassAFactory,依赖关系清晰可见,单元测试时只需要模拟工厂返回对应实例即可,完全不需要耦合DI容器。后续如果IClassA的实现、生命周期有调整,只需要修改工厂内部逻辑,不需要改动业务代码,符合开闭原则。额外编写工厂接口和实现的代码量很低,换来的可维护性收益远大于成本。
更优的简化方案

如果你的项目运行在.NET 5及以上版本,微软原生DI已经支持Func<T>类型的自动注入,不需要你手动编写工厂类:

  1. 服务注册时保持原有配置即可,如果需要每次返回新实例可以注册为AddTransient,需要Scope生命周期则保持AddScoped
services.AddTransient<IClassA, ClassA>();
  1. 在ClassA的构造函数中直接注入Func<IClassA>类型的工厂委托:
class ClassA : IClassA
{
    private readonly Func<IClassA> _classAFactory;
    public ClassA(ILogger<ClassA> logger, Func<IClassA> classAFactory)
    {
        _classAFactory = classAFactory;
    }
    public void Foo()
    {
        while(true)
        {
            var classA = _classAFactory();
            // 业务逻辑
        }
    }
}

这种方式不需要手动编写任何工厂类和接口,同时保留了工厂模式的所有优势,是运行时获取服务实例的最优选择。

内容的提问来源于stack exchange,提问作者Kris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 13:36:04