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
相关产品推荐
相关产品推荐

