寻找类似ActivatorUtilities.CreateInstance的显式参数绑定DI实例化方法
依赖注入中显式绑定构造函数参数的标准方案
我们有如下实现了ISomething接口的Something类,其构造函数需要传入字符串参数someText和IAwesomeifier接口实例:
public class Something : ISomething { public string SomeText { get; } public IAwesomeifier Awesomeifier { get; } public Something(string someText, IAwesomeifier awesomeifier) { this.SomeText = someText ?? throw new ArgumentNullException(nameof(someText)); this.Awesomeifier = awesomeifier ?? throw new ArgumentNullException(nameof(awesomeifier)); } // ... 其他业务方法... }
目前可以通过ActivatorUtilities结合依赖注入(使用Microsoft.Extensions.Hosting和Microsoft.Extensions.DependencyInjection)实例化该类,代码如下:
private static IHost BuildHost() { var builder = Host.CreateApplicationBuilder(); var services = builder.Services; services.AddSingleton<IAwesomeifier, Awesomeifier>(); services.AddSingleton<ISomething>(provider => ActivatorUtilities.CreateInstance<Something>( provider, "Here's the text to be awesomeified")); return builder.Build(); }
但这种方式依赖构造函数的参数顺序,一旦参数顺序变动就会出错。有没有标准方案可以显式绑定参数值与目标参数,比如类似指定someText:的写法?
可行的标准方案
方案1:使用.NET 6+新增的匿名类型重载(最接近需求)
从.NET 6开始,ActivatorUtilities提供了支持匿名类型传递命名参数的重载,你可以直接通过匿名对象指定参数名和对应的值,DI容器会自动匹配构造函数的参数,同时自动解析其他依赖的服务:
private static IHost BuildHost() { var builder = Host.CreateApplicationBuilder(); var services = builder.Services; services.AddSingleton<IAwesomeifier, Awesomeifier>(); services.AddSingleton<ISomething>(provider => ActivatorUtilities.CreateInstance<Something>( provider, new { someText = "Here's the text to be awesomeified" })); return builder.Build(); }
方案2:手动构造实例(最直观)
如果不想依赖ActivatorUtilities,可以直接从服务提供者中获取所需的依赖服务,然后手动调用构造函数,这种方式完全显式,不存在参数顺序问题:
private static IHost BuildHost() { var builder = Host.CreateApplicationBuilder(); var services = builder.Services; services.AddSingleton<IAwesomeifier, Awesomeifier>(); services.AddSingleton<ISomething>(provider => { var awesomeifier = provider.GetRequiredService<IAwesomeifier>(); return new Something("Here's the text to be awesomeified", awesomeifier); }); return builder.Build(); }
方案3:工厂类封装(适合复杂场景)
如果需要复用参数绑定逻辑,或者构造逻辑较为复杂,可以创建工厂类来分离参数和DI依赖:
public class SomethingFactory { private readonly IAwesomeifier _awesomeifier; public SomethingFactory(IAwesomeifier awesomeifier) { _awesomeifier = awesomeifier; } public Something Create(string someText) { return new Something(someText, _awesomeifier); } }
然后在DI注册时使用工厂类:
private static IHost BuildHost() { var builder = Host.CreateApplicationBuilder(); var services = builder.Services; services.AddSingleton<IAwesomeifier, Awesomeifier>(); services.AddSingleton<SomethingFactory>(); services.AddSingleton<ISomething>(provider => { var factory = provider.GetRequiredService<SomethingFactory>(); return factory.Create("Here's the text to be awesomeified"); }); return builder.Build(); }
内容的提问来源于stack exchange,提问作者Bob Vesterman
相关产品推荐
相关产品推荐

