如何在C#依赖注入中正确创建带构造参数的对象?
如何通过依赖注入创建带运行时参数的对象
针对你需要为每个从INI读取的Id创建SomeClass实例的场景,下面提供几种规范的原生DI实现方式,避免直接new的同时,保留DI自动注入其他依赖的能力:
方案一:基于抽象工厂+ActivatorUtilities(推荐)
这种方式既保留工厂模式的灵活性,又能让DI容器负责解析SomeClass的其他依赖(比如后续添加的ILogger、其他服务等),无需修改工厂代码。
步骤1:定义工厂接口
public interface ISomeClassFactory { SomeClass Create(int id); }
步骤2:实现工厂(依赖IServiceProvider)
利用原生DI的ActivatorUtilities工具类,让容器自动解析SomeClass的所有依赖,仅传入运行时确定的Id参数:
public class SomeClassFactory : ISomeClassFactory { private readonly IServiceProvider _serviceProvider; public SomeClassFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public SomeClass Create(int id) { // 容器会自动注入SomeClass构造函数中除了id之外的其他依赖 return ActivatorUtilities.CreateInstance<SomeClass>(_serviceProvider, id); } }
步骤3:注册工厂和服务
var builder = Host.CreateApplicationBuilder(e.Args); // 注册SomeClass builder.Services.AddTransient<SomeClass>(); // 注册工厂 builder.Services.AddTransient<ISomeClassFactory, SomeClassFactory>();
步骤4:使用工厂创建实例
在需要创建实例的地方,通过构造函数注入工厂,然后批量创建:
// 假设在某个服务中注入工厂 public class YourBusinessService { private readonly ISomeClassFactory _someClassFactory; public YourBusinessService(ISomeClassFactory someClassFactory) { _someClassFactory = someClassFactory; } public void ProcessIds() { List<int> ids = readIdsFromIni(); foreach(var id in ids) { SomeClass instance = _someClassFactory.Create(id); // 处理实例逻辑 } } }
方案二:直接使用ActivatorUtilities(简化版)
如果不需要抽象工厂的解耦(比如场景简单,不需要替换工厂实现),可以直接在需要创建实例的地方注入IServiceProvider,然后调用ActivatorUtilities:
public class YourBusinessService { private readonly IServiceProvider _serviceProvider; public YourBusinessService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public void ProcessIds() { List<int> ids = readIdsFromIni(); foreach(var id in ids) { SomeClass instance = ActivatorUtilities.CreateInstance<SomeClass>(_serviceProvider, id); // 处理实例逻辑 } } }
为什么这比直接new好?
如果后续SomeClass的构造函数添加了新的依赖(比如日志服务):
public class SomeClass { public SomeClass(int id, ILogger<SomeClass> logger) { Id = id; _logger = logger; } public int Id {get;} private readonly ILogger<SomeClass> _logger; }
使用上述方案时,DI容器会自动注入ILogger<SomeClass>,无需修改创建实例的代码;而直接new的话,需要手动传入所有新添加的依赖,维护成本更高。
内容的提问来源于stack exchange,提问作者Petr Daricek
相关产品推荐
相关产品推荐

