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

.NET Core依赖注入:工厂方法注册服务为何性能更慢?

为什么工厂方法注册服务反而比常规注册慢?

这个问题挺有意思的——我刚看到你的测试结果时也有点惊讶,毕竟直觉上自己手动new对象好像应该绕开DI容器的解析逻辑,更快才对。但实际测试数据很明确,工厂方法注册反而略慢,这背后其实是.NET依赖注入容器的内部优化机制在起作用。

核心原因分析

1. 常规注册的表达式树编译优化

当你使用services.AddTransient<IServiceXxx, ServiceXxx>这种常规类型注册时,.NET DI容器在构建ServiceProvider的阶段,会为每个服务生成并编译表达式树。这个过程相当于提前把对象的构造逻辑转换成了高效的IL代码,后续每次调用GetRequiredService<T>时,直接执行这段编译好的代码,几乎没有额外的间接开销。

而工厂方法注册的是一个lambda委托:

services.AddTransient<IServiceXxx>(sp => new ServiceXxx(new ServiceA(), new ServiceB()) );

每次获取服务时,容器都需要调用这个委托。虽然委托调用的开销不大,但和编译好的表达式树比起来,多了一层委托调用的间接性,这在千万次循环的测试中会累积出明显的差异。

2. DI容器的内部服务创建器优化

常规注册时,容器会为每个服务维护一个预初始化的服务创建器(ServiceCreator),这个创建器是专门针对该服务的实例逻辑优化过的。当你调用GetRequiredService<T>时,容器几乎是直接跳转到对应的创建逻辑,没有额外的查找或判断步骤。

而工厂方法注册的服务,容器需要先定位到对应的工厂委托,再执行委托创建实例。这中间多了一步“查找并调用委托”的过程,单次开销微乎其微,但在高频调用场景下就会显现出差距。

3. JIT编译的优化差异

容器生成的表达式树代码,JIT编译器可以做更充分的优化——比如内联、消除冗余操作,因为这段代码是容器根据DI场景生成的,结构更规整。而你手动编写的lambda表达式,JIT虽然也会优化,但优化的针对性不如容器生成的代码强,最终执行效率略低。

补充验证小建议

如果你把工厂方法里的手动new改成让容器解析依赖:

services.AddTransient<IServiceXxx>(sp => new ServiceXxx(sp.GetRequiredService<IServiceA>(), sp.GetRequiredService<IServiceB>()) );

再测试性能,会发现差距更大——因为此时不仅有委托调用的开销,还多了两次GetRequiredService的调用。这也从侧面印证了常规注册时容器对整个依赖链的优化更彻底。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:37:37