DryIoc注册带ID多实例 实现按ID构造注入对应实例
DryIoc 按传入ID匹配ServiceKey解析实例的实现方案
报错核心原因:DryIoc默认不会将Func<string, T>委托的入参自动识别为服务注册的serviceKey,默认逻辑会把传入的字符串当作服务构造的入参去匹配,因此找不到对应注册项抛出异常。
不需要自定义静态Holder类,直接用DryIoc原生能力即可实现需求,两种常用方案如下:
方案1:显式注册按键解析的委托(最小改动)
不需要修改任何业务类代码,只需要补充一行委托注册,告诉容器Func<string, MyInterface>的实现逻辑即可:
using DryIoc; public interface MyInterface { string Id { get; } } public class MyImpl : MyInterface { public string Id { get; } public MyImpl(string id) => Id = id; } public class User { public MyInterface Obj { get; } public User(string id, Func<string, MyInterface> getObj) => Obj = getObj(id); } class Program { static void Main() { Container container = new(); container.RegisterInstance<MyInterface>(new MyImpl("A"), serviceKey: "A"); container.RegisterInstance<MyInterface>(new MyImpl("B"), serviceKey: "B"); // 新增这行即可:注册按ID取实例的委托,完全复用容器的实例管理能力 container.RegisterDelegate<Func<string, MyInterface>>(c => id => c.Resolve<MyInterface>(serviceKey: id)); container.Register<User>(); // 原有调用逻辑完全不变,运行无异常 var user = container.Resolve<Func<string, User>>()("A"); // user.Obj.Id 结果为 "A" } }
方案2:通过Made参数配置依赖解析规则
如果不想单独注册委托,可以在注册服务时通过Made参数直接配置依赖的解析规则,把传入的ID参数映射为对应依赖的serviceKey,这种写法可以简化业务类的构造函数,不需要手动调用委托取实例:
// 简化后的User类,直接依赖目标实例,不需要注入Func public class User { public MyInterface Obj { get; } public User(string id, MyInterface obj) => Obj = obj; } class Program { static void Main() { Container container = new(); container.RegisterInstance<MyInterface>(new MyImpl("A"), serviceKey: "A"); container.RegisterInstance<MyInterface>(new MyImpl("B"), serviceKey: "B"); // 注册User时指定:MyInterface类型的依赖,用解析链路中传入的string类型ID作为serviceKey解析 container.Register<User>(made: Parameters.Of .Type<MyInterface>(serviceKey: req => req.Parent.ResolutionArguments.FirstOrDefault(arg => arg is string) as string ) ); var userFactory = container.Resolve<Func<string, User>>(); var userA = userFactory("A"); // 自动注入Key为A的MyImpl实例 var userB = userFactory("B"); // 自动注入Key为B的MyImpl实例 } }
补充场景适配
你提到的Service/ViewModel多层依赖场景,用方案2的逻辑同样可以实现,不需要静态Holder类:
interface IService { string Id { get; } } class Service : IService { public string Id { get; } public Service(string id) => Id = id; } interface IServiceUser { IService Service { get; } } class ServiceUser : IServiceUser { public IService Service { get; } public ServiceUser(IService service) => Service = service; } class ViewModel { public ViewModel(IServiceUser serviceUser) { Console.WriteLine(serviceUser.Service.Id); } } static class Program { static void Main() { Container container = new(); // 直接注册带Key的服务实例,不需要存入静态字典 container.RegisterInstance<IService>(new Service("A"), serviceKey: "A"); container.RegisterInstance<IService>(new Service("B"), serviceKey: "B"); // 配置IService依赖按传入的ID参数解析 container.Register<IServiceUser, ServiceUser>(made: Parameters.Of .Type<IService>(serviceKey: req => req.Parent.ResolutionArguments.FirstOrDefault(a => a is string) as string ) ); container.Register<ViewModel>(); var createVm = container.Resolve<Func<string, ViewModel>>(); var vmA = createVm("A"); // 控制台输出A var vmB = createVm("B"); // 控制台输出B } }
注意:如果解析链路中存在多个string类型入参,建议在取serviceKey时增加参数名校验,避免匹配到错误的参数值,示例逻辑:
req => { var args = req.Parent.ResolutionArguments.ToArray(); var parameters = req.Parent.SelectedConstructor?.GetParameters() ?? Array.Empty<ParameterInfo>(); for (var i = 0; i < parameters.Length; i++) { if (parameters[i].Name == "id" && i < args.Length && args[i] is string targetId) return targetId; } return null; }
内容的提问来源于stack exchange,提问作者ttact
相关产品推荐
相关产品推荐

