DryIoc 5.0.0条件注册INotify未匹配对应父服务问题
DryIoc 5.0.0 条件注册INotify实现的问题
环境与现有代码
我使用.NET Framework搭配DryIoc 5.0.0版本,现有以下类:
public class AMessageService : IHandle { public AMessageService (INotify notify) { //... } }
public class BMessageService : IHandle { public BMessageService (INotify notify) { //... } }
初始注册代码:
// ... container.Register<IHandle, AMessageService>(serviceKey: nameof(AMessageService)); container.Register<IHandle, BMessageService>(serviceKey: nameof(BMessageService)); // ...
可通过以下构造函数解析所有IHandle实现:
public SequentialEventAggregator(params IHandle[] handlers) // <-- 得到AMessageService和BMessageService
为支持多个INotify实现,创建NotifyComposite类:
public class NotifyComposite: INotify { private readonly IEnumerable<INotify> _notificators; public NotifyComposite(IEnumerable<INotify> notificators) { _notificators = notificators; } public void Notify() { _notificators.ToList().ForEach(n => n.Notify()); } }
更新后的注册代码:
// ... container.Register<IHandle, AMessageService>(serviceKey: nameof(AMessageService)); container.Register<IHandle, BMessageService>(serviceKey: nameof(BMessageService)); container.Register<INotify, NotifyComposite>(); // ...
问题描述
尝试注册带条件的多个INotify实现时出现异常:
// ... container.Register<IHandle, AMessageService>(serviceKey: nameof(AMessageService)); container.Register<IHandle, BMessageService>(serviceKey: nameof(BMessageService)); container.Register<INotify, NotifyComposite>(); // 使用Parent.Parent是因为第一个父级是NotifyComposite container.Register<INotify, EmailChannelA>(setup: Setup.With(condition: r => r.Parent.Parent.ImplementationType == typeof(AMessageService))); container.Register<INotify, EmailChannelB>(setup: Setup.With(condition: r => r.Parent.Parent.ImplementationType == typeof(BMessageService))); // <-- 无法正常工作 container.Register<INotify, ChatChannel>(); // ...
预期结果
- 解析
AMessageService时,notify为包含EmailChannelA和ChatChannel的NotifyComposite - 解析
BMessageService时,notify为包含EmailChannelB和ChatChannel的NotifyComposite
当前结果
- 解析
AMessageService时,notify为包含EmailChannelA和ChatChannel的NotifyComposite - 解析
BMessageService时,notify仍为包含EmailChannelA和ChatChannel的NotifyComposite
其他发现
- 移除
container.Register<IHandle, AMessageService>(serviceKey: nameof(AMessageService))后功能正常,似乎setup.condition调用时解析上下文始终是第一个注册的IHandle,但原因不明 - 尝试过
openResolutionScope等属性,无效果 - 查阅过DryIoc基于上下文的解析文档,但似乎解决的是不同问题
- 该功能在旧版DryIoc(2.x.x)中可以正常工作
- 在
AMessageService和BMessageService中使用Made.Of会导致代码重复,我希望避免这种情况,比如后续所有不绑定条件、需注入到所有服务的INotify实现
解决方案
问题根源在于DryIoc 5.x版本中,依赖固定层级的Parent.Parent上下文判断不可靠,解析栈的层级可能因版本变化而改变。改用遍历整个解析栈的方式判断上下文,同时确保NotifyComposite每次解析都能收集到符合当前上下文的INotify实例:
// 先注册通用的ChatChannel(无绑定条件,所有服务都能获取) container.Register<INotify, ChatChannel>(); // 注册EmailChannelA,条件为解析栈中存在AMessageService container.Register<INotify, EmailChannelA>(setup: Setup.With(condition: r => r.Stack.Any(s => s.ImplementationType == typeof(AMessageService)))); // 注册EmailChannelB,条件为解析栈中存在BMessageService container.Register<INotify, EmailChannelB>(setup: Setup.With(condition: r => r.Stack.Any(s => s.ImplementationType == typeof(BMessageService)))); // 注册NotifyComposite作为INotify的默认实现,显式指定Transient复用策略确保每次解析都重新收集实例 container.Register<INotify, NotifyComposite>(setup: Setup.With(reuse: Reuse.Transient)); // 最后注册IHandle实现 container.Register<IHandle, AMessageService>(serviceKey: nameof(AMessageService)); container.Register<IHandle, BMessageService>(serviceKey: nameof(BMessageService));
说明
- 解析栈判断:使用
r.Stack.Any()遍历整个解析上下文栈,检查是否包含目标服务类型,相比固定层级的Parent.Parent更稳定,不受DryIoc版本升级导致的解析链变化影响。 - Transient复用策略:显式指定
NotifyComposite为Transient(DryIoc默认也是Transient,但显式声明更清晰),确保每次解析IHandle实例时,都会创建新的NotifyComposite并收集当前上下文符合条件的INotify实现。 - 注册顺序:先注册所有
INotify实现,再注册NotifyComposite和IHandle,确保DryIoc能正确收集所有符合条件的实例。
内容的提问来源于stack exchange,提问作者Julia
相关产品推荐
相关产品推荐

