能否在.NET Core原生DI容器中实现类似Ninject的命名绑定?
.NET Core原生DI实现类似Ninject的命名绑定
.NET Core原生DI容器本身并没有内置像Ninject那样直接的命名绑定功能,但咱们可以通过几种实用的方式来实现类似的效果,满足你根据名称获取IValidationRule不同实现的需求。
方案一:自定义服务工厂(兼容所有.NET Core版本)
这种方式适用于所有.NET Core版本,核心思路是通过一个工厂类来管理不同实现的名称映射,然后从容器中获取对应的实例。
步骤1:定义工厂接口
public interface IValidationRuleFactory { IValidationRule GetRule(string ruleName); }
步骤2:实现工厂类
在工厂类中维护名称与实现类的映射,同时注入IServiceProvider来获取实例:
public class ValidationRuleFactory : IValidationRuleFactory { private readonly IServiceProvider _serviceProvider; private readonly Dictionary<string, Type> _ruleTypeMap = new() { {"first", typeof(FirstValidationRule)}, {"second", typeof(SecondValidationRule)} }; public ValidationRuleFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IValidationRule GetRule(string ruleName) { if (_ruleTypeMap.TryGetValue(ruleName, out var ruleType)) { return (IValidationRule)_serviceProvider.GetRequiredService(ruleType); } throw new ArgumentException($"找不到名称为「{ruleName}」的验证规则"); } }
步骤3:注册服务
先注册所有的IValidationRule实现类,再注册工厂:
services.AddSingleton<FirstValidationRule>(); services.AddSingleton<SecondValidationRule>(); services.AddSingleton<IValidationRuleFactory, ValidationRuleFactory>();
步骤4:使用工厂获取实例
var ruleFactory = provider.GetRequiredService<IValidationRuleFactory>(); var firstRule = ruleFactory.GetRule("first"); // 获取FirstValidationRule实例 var secondRule = ruleFactory.GetRule("second"); // 获取SecondValidationRule实例
方案二:使用键服务注入(.NET 8及以上版本)
从.NET 8开始,原生DI新增了**键服务(Keyed Services)**功能,这是官方提供的类似命名绑定的解决方案,用法更简洁。
步骤1:注册键服务
直接通过AddKeyedSingleton(或对应的生命周期方法)注册带名称(键)的服务:
// .NET 8+ 专属语法 services.AddKeyedSingleton<IValidationRule, FirstValidationRule>("first"); services.AddKeyedSingleton<IValidationRule, SecondValidationRule>("second");
步骤2:获取指定键的服务
可以直接通过GetRequiredKeyedService方法按键获取实例:
var firstRule = provider.GetRequiredKeyedService<IValidationRule>("first"); var secondRule = provider.GetRequiredKeyedService<IValidationRule>("second");
如果需要在构造函数中注入指定键的服务,可以使用[FromKeyedServices]特性:
public class SomeService { public SomeService([FromKeyedServices("first")] IValidationRule firstRule) { // 使用firstRule } }
补充说明
原生DI的设计理念更偏向于显式依赖注入,即通过构造函数明确声明所需的依赖,而不是动态根据名称获取。但上述两种方式都能很好地模拟命名绑定的场景,你可以根据项目的.NET版本选择合适的方案。
内容的提问来源于stack exchange,提问作者gneric
相关产品推荐
相关产品推荐

