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

DryIoc中IfAlreadyRegistered.Keep评估时机与服务解析优先级问题

DryIoc注册优先级与默认服务替换问题解答

核心问题答案

按你描述的注册顺序(ServiceA先、ServiceB后),且仅ServiceA设置IfAlreadyRegistered.Keep的情况下:

  • 若ServiceB注册时未指定IfAlreadyRegistered参数(DryIoc默认是Throw),注册ServiceB时会直接抛出异常,因为IService已有ServiceA的注册。
  • 若ServiceB注册时指定了IfAlreadyRegistered.Append,解析IService单个实例会返回ServiceB(DryIoc默认返回最后注册的同服务类型实例);若解析IEnumerable<IService>会按注册顺序返回[A, B]。
  • 若ServiceB注册时也指定了IfAlreadyRegistered.Keep,则ServiceB的注册会被跳过,解析得到的是ServiceA实例。

你测试中“无论顺序都得到ServiceA”的情况,大概率是因为注册ServiceB时也使用了IfAlreadyRegistered.Keep,导致后注册的实现被跳过,始终保留先注册的实例。

关于IfAlreadyRegistered.Keep的工作机制

IfAlreadyRegistered.Keep是在注册阶段生效的规则,作用是:当尝试注册某个服务类型的实现时,如果该服务类型已有注册项,就放弃当前注册请求,保留已有的注册。它和Throw的差异仅在于:Throw会直接抛出异常,而Keep会静默跳过当前注册。

实现“默认服务可被替换”的最优方案

你想要共享库提供默认实现ServiceA,第三方注册ServiceB时优先使用B,推荐两种可靠方式:

方式1:默认注册用Keep,第三方注册用Replace

  • 共享库中注册默认实现:
    container.Register<IService, ServiceA>(Reuse.Singleton, ifAlreadyRegistered: IfAlreadyRegistered.Keep);
    
  • 第三方需要替换时,注册ServiceB时使用Replace覆盖默认:
    container.Register<IService, ServiceB>(Reuse.Singleton, ifAlreadyRegistered: IfAlreadyRegistered.Replace);
    
    这种方式下,无论注册顺序如何:
    • 若第三方先注册ServiceB,共享库的ServiceA注册会被跳过,解析得到B;
    • 若共享库先注册ServiceA,第三方的Replace会直接覆盖,解析得到B。

方式2:条件注册默认实现

通过DryIoc的条件注册,让ServiceA仅在IService未被注册时才生效,无需第三方额外指定Replace:

container.Register<IService, ServiceA>(Reuse.Singleton,
    ifAlreadyRegistered: IfAlreadyRegistered.Keep,
    condition: r => !container.IsRegistered<IService>());

这样只要第三方在任何时机注册了IService的实现(比如ServiceB),共享库的ServiceA注册都会被跳过,自动优先使用第三方的实现。

内容的提问来源于stack exchange,提问作者prlcutting

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:25:23