.NET/C# DI 如何解析构造函数含不同字符串参数的对象实例
方案说明
当前设计存在的问题
你当前的设计核心问题在于IMyObject的注册逻辑不符合DI容器的常规使用规则:MyObject构造函数需要的字符串是运行时才能确定的动态参数(从配置的路径中读取),直接将IMyObject注册为Transient服务时,DI容器无法自动提供这个动态参数,启动时会直接抛出依赖缺失异常。
最优实现方案
推荐使用抽象工厂+ActivatorUtilities的组合方案,既完全符合DI原则,也能满足动态传参创建实例的需求,同时避免后续业务迭代时频繁修改工厂代码。
步骤1:定义工厂接口与实现
// 工厂接口 public interface IMyObjectFactory { IMyObject Create(string filePath); } // 工厂实现,依赖IServiceProvider即可 public class MyObjectFactory : IMyObjectFactory { private readonly IServiceProvider _serviceProvider; public MyObjectFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IMyObject Create(string filePath) { // 第二个参数开始传入构造函数需要的动态参数,其他依赖由DI容器自动注入 return ActivatorUtilities.CreateInstance<MyObject>(_serviceProvider, filePath); } }
步骤2:调整服务注册逻辑
// 注册工厂为单例 serviceCollection.AddSingleton<IMyObjectFactory, MyObjectFactory>(); // 删除原本的IMyObject注册逻辑,实例由工厂创建 // serviceCollection.AddTransient<IMyObject, MyObject>();
步骤3:在MyService中使用工厂创建实例
public class MyService : IMyService { private readonly IMyObjectFactory _objectFactory; private readonly IOtherService _otherService; private readonly IOptions<FilePaths> _filePaths; public MyService(IOtherService otherService, IOptions<FilePaths> filePaths, IMyObjectFactory objectFactory) { _otherService = otherService; _filePaths = filePaths; _objectFactory = objectFactory; } public void WorkWithObjects() { // 传入不同路径创建不同行为的实例 var objectA = _objectFactory.Create(_filePaths.Value.PathA); var objectB = _objectFactory.Create(_filePaths.Value.PathB); // 执行业务逻辑 } }
方案优势
- 完全符合DI原则:所有依赖都由DI容器注入,不会出现硬编码实例化的问题
- 可维护性高:后续如果
MyObject新增其他需要DI注入的依赖(比如ILogger<MyObject>、IDbContext等),只需要修改MyObject的构造函数即可,工厂代码不需要做任何调整 - 对象初始化完整:不需要构造完成后再赋值参数,避免出现半初始化对象导致的空引用问题
你之前尝试方案的误区说明
- 工厂硬编码实例化:你之前担心的工厂需要同步修改的问题,是因为直接在工厂中
new MyObject(xxx)导致的,使用ActivatorUtilities创建实例后不存在这个问题 ActivatorUtilities传参:ActivatorUtilities.CreateInstance方法支持传入任意数量的构造参数,会自动按类型匹配到构造函数的对应参数,你之前没找到传参方式是没有注意到该方法的可变参数重载- 构造后赋值:确实会导致代码整洁度下降,同时存在对象未完全初始化就被调用的风险,不推荐使用
内容的提问来源于stack exchange,提问作者MichaelS
相关产品推荐
相关产品推荐

