如何在Microsoft.Extensions.DependencyInjection中实现简化的参数化依赖注入
解决动态依赖注入的现场定制需求
针对在UI应用中使用Microsoft.Extensions.DependencyInjection时,需要在使用现场动态补充依赖、避免大量样板代码的问题,有几种简洁的实现方式:
1. 自定义WithTransient扩展方法
你可以实现一个扩展方法,在新的服务作用域中临时注册动态依赖,完全贴合你期望的用法:
扩展方法实现
public static IServiceProvider WithTransient<T>(this IServiceProvider provider, T instance) where T : class { var scopeFactory = provider.GetRequiredService<IServiceScopeFactory>(); var scope = scopeFactory.CreateScope(); var scopedServices = scope.ServiceCollection; scopedServices.AddTransient(_ => instance); return scope.ServiceProvider; }
使用方式
var workspacePath = new WorkspacePath(someWorkspacePathString); using var scopedProvider = serviceProvider.WithTransient(workspacePath); var workspace = scopedProvider.GetRequiredService<IWorkspace>();
注意:返回的
IServiceProvider是新的作用域,需用using包裹确保释放,避免内存泄漏。
2. 用ActivatorUtilities直接构造实例
如果目标服务仅需补充少数动态参数,其余依赖已在容器注册,可直接用ActivatorUtilities结合容器已有依赖构造实例:
var workspacePath = new WorkspacePath(someWorkspacePathString); var workspace = ActivatorUtilities.CreateInstance<Workspace>(serviceProvider, workspacePath);
这种方式无需额外注册,跳过容器解析逻辑,适合参数较少的场景。
3. 通用工厂封装(减少大量类型的样板代码)
封装通用工厂,只需一次注册即可支持所有类型的动态参数构造:
通用工厂接口与实现
public interface IGenericFactory<T> { T Create(params object[] parameters); } public class GenericFactory<T> : IGenericFactory<T> { private readonly IServiceProvider _provider; public GenericFactory(IServiceProvider provider) { _provider = provider; } public T Create(params object[] parameters) { return ActivatorUtilities.CreateInstance<T>(_provider, parameters); } }
注册与使用
// 启动时注册 services.AddScoped(typeof(IGenericFactory<>), typeof(GenericFactory<>)); // 使用现场 var factory = serviceProvider.GetRequiredService<IGenericFactory<IWorkspace>>(); var workspace = factory.Create(new WorkspacePath(someWorkspacePathString));
关于键控服务的局限性
正如你所说,.NET 8的键控服务要求键在容器配置阶段提前确定,无法支持运行时动态生成的参数(如用户选择的工作区路径),因此上述方案更适配你的场景。
内容的提问来源于stack exchange,提问作者Bent Rasmussen
相关产品推荐
相关产品推荐

