并行for循环中向容器提供运行时数据的DI实现合理性探讨
问题与代码示例
业务层代码
public class Factor1(int FactorX, int FactorY) : IFactors; public class Factor2(int FactorX, int FactorY, int FZ) : IFactors; public interface IFactors { int FactorX { get; set; } int FactorY { get; set; } } public class BusinessLayerClass1 { IFactors _factorObj; public BusinessLayerClass1(IFactors factorObj) { _factorObj = factorObj; } public void Call() => new BusinessLayerClass2(_factorObj).ShowFactors(); } public class BusinessLayerClass2 { IFactors _factorObj; public BusinessLayerClass2(IFactors factorObj) { _factorObj = factorObj; } public void ShowFactors() { Debug.WriteLine(String.Concat(_factorObj.FactorX.ToString(), " - " + _factorObj.FactorY.ToString())); } }
主程序代码
using SimpleInjector; class Program { public static void Main(string[] args) { List<Task> tasks = new List<Task>(); for (var i = 0; i < 10; i++) { tasks.Add(Task.Factory.StartNew((num) => { int num_ = (int)num; var factorObj = new Factor1() { FactorX = num_, FactorY = num_ + 1 }; var container = new Container(); var lifestyle = Lifestyle.Transient; container.Register<BusinessLayerClass1>(lifestyle); container.Register<BusinessLayerClass2>(lifestyle); container.RegisterInstance<IFactors>(factorObj); container.Verify(); var BL = container.GetInstance<BusinessLayerClass1>(); BL.Call(); }, i)); } Task.WaitAll(tasks.ToArray()); } }
疑问
当前代码可运行,但存在以下疑问:
- 该DI实现方式是否正确?
- 若正确,是否有更便捷的优化方案?
- 若不正确,针对此场景应如何正确实现DI?
回答
一、当前实现的问题
你的DI实现不符合最佳实践,存在明显问题:
- 容器重复创建:每个Task里都实例化新的
Container,DI容器的核心价值是作为全局服务容器复用,重复创建会完全丧失DI的优势,还带来不必要的性能开销。 - 手动实例化依赖:
BusinessLayerClass1.Call()里直接new BusinessLayerClass2(_factorObj),违背了DI的核心原则——依赖应通过容器注入而非手动创建,导致类之间耦合度高,无法利用容器的生命周期管理能力。 IFactors注册语义错误:RegisterInstance用于注册单例实例,但这里每个Task的Factor1是独立的,用该方法虽然能运行,但语义完全错误,应该用工厂方式处理动态实例的创建。
二、正确的优化实现方案
针对你的场景(Factor1需异步创建,业务类依赖IFactors),优化步骤如下:
1. 重构业务层,消除手动实例化
修改BusinessLayerClass1,让BusinessLayerClass2通过构造函数注入,彻底交给容器管理依赖:
public class BusinessLayerClass1 { private readonly BusinessLayerClass2 _businessLayerClass2; // 直接注入BusinessLayerClass2,而非IFactors public BusinessLayerClass1(BusinessLayerClass2 businessLayerClass2) { _businessLayerClass2 = businessLayerClass2; } public void Call() => _businessLayerClass2.ShowFactors(); }
2. 全局初始化容器,复用实例
DI容器应在程序启动时初始化一次,而非每个Task重复创建。针对每个Task的动态Factor1实例,利用SimpleInjector的GetInstance重载传入自定义依赖:
优化后的主程序代码
using SimpleInjector; class Program { public static void Main(string[] args) { // 全局初始化一次容器 var container = new Container(); // 注册业务类为Transient(每次获取都创建新实例) container.Register<BusinessLayerClass1>(Lifestyle.Transient); container.Register<BusinessLayerClass2>(Lifestyle.Transient); container.Verify(); List<Task> tasks = new List<Task>(); for (var i = 0; i < 10; i++) { int num = i; // 捕获循环变量,避免闭包问题 tasks.Add(Task.Run(() => { // 异步创建Factor1实例 var factorObj = new Factor1(num, num + 1); // 传入自定义的IFactors实例,获取业务类对象 var bl1 = container.GetInstance<BusinessLayerClass1>(new[] { factorObj }); bl1.Call(); })); } Task.WaitAll(tasks.ToArray()); } }
注:用Task.Run替代Task.Factory.StartNew,是因为Task.Run更适合异步操作,能避免StartNew的一些潜在问题。
3. 进阶优化:用工厂封装Factor1的创建
如果Factor1的创建逻辑复杂,可封装成工厂类,让业务类通过工厂按需创建实例:
public interface IFactorFactory { IFactors CreateFactor1(int x, int y); } public class FactorFactory : IFactorFactory { public IFactors CreateFactor1(int x, int y) => new Factor1(x, y); }
然后在容器中注册工厂:
container.Register<IFactorFactory, FactorFactory>(Lifestyle.Singleton);
业务类注入工厂后,可灵活创建IFactors实例,更符合单一职责原则。
三、总结
当前的DI实现不正确,核心问题是容器重复创建、手动实例化依赖、注册方式语义错误。优化后通过全局复用容器、消除手动实例化、正确处理动态依赖的方式,既符合DI最佳实践,又满足Factor1异步创建的需求。
内容的提问来源于stack exchange,提问作者lowdegeneration
相关产品推荐
相关产品推荐

