Microsoft.Extensions.DependencyInjection解析服务时如何传入额外构造参数
解决方案
你可以直接从DI容器的服务注册描述中获取ISomething对应的实现类型,无需预先创建冗余的默认实例,该方案对现有代码逻辑完全无侵入,也不需要修改第三方实现类。
具体实现思路
- 注册服务时将
IServiceCollection本身也注册到容器中,方便运行时查询服务注册信息 - 需要构造带参实例时,直接从服务描述中取出实现类型,传入
ActivatorUtilities.CreateInstance即可
完整代码示例
using System; using System.Linq; using Microsoft.Extensions.DependencyInjection; namespace App { public interface ISomething { void DoSomething() => Console.WriteLine(nameof(DoSomething)); } public class Something: ISomething { public Something() => Console.WriteLine($"{this.GetType().Name} created"); public Something(object context) => Console.WriteLine($"{this.GetType().Name} created with {context}"); } static class Program { private static IServiceProvider BuildServices() { var services = new ServiceCollection() .AddTransient<ISomething, Something>(); // 注册服务集合本身,用于后续查询服务注册信息 services.AddSingleton(services); return services.BuildServiceProvider(); } static ISomething CreateSomething(IServiceProvider serviceProvider) => serviceProvider.GetRequiredService<ISomething>(); static ISomething CreateSomethingWithContext(IServiceProvider serviceProvider, object context) { // 获取服务注册集合 var allServices = serviceProvider.GetRequiredService<IServiceCollection>(); // 查找ISomething对应的服务注册 var serviceDesc = allServices.FirstOrDefault(d => d.ServiceType == typeof(ISomething)); if (serviceDesc == null) throw new InvalidOperationException("ISomething服务未注册"); // 直接从注册信息中获取实现类型,无需创建任何实例 var implementationType = serviceDesc.ImplementationType; if (implementationType == null) throw new InvalidOperationException("无法获取ISomething的实现类型,当前服务为工厂/实例注册"); // 构造带额外参数的实例 return (ISomething)ActivatorUtilities.CreateInstance(serviceProvider, implementationType, context); } static void Main() { var serviceProvider = BuildServices(); CreateSomething(serviceProvider); CreateSomethingWithContext(serviceProvider, Guid.NewGuid()); } } }
方案优势
- 无冗余实例创建,避免不必要的性能损耗和初始化副作用
- 原有使用
GetRequiredService<ISomething>()的代码无需任何修改 - 不需要调整第三方实现类的代码,符合约束条件
注意事项
如果你的ISomething是通过工厂方法或者实例注册的,ImplementationType属性会为null,这种场景下才需要考虑其他兼容方案,普通类型注册的场景可以直接使用该方案。
内容的提问来源于stack exchange,提问作者noseratio
相关产品推荐
相关产品推荐

