You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 10:27:40