有时,我发现自己处于仅在满足特定条件时才需要解决服务的情况。例如,用户可能选择发送电子邮件或短信通知。我想根据用户的选择延迟加载电子邮件或短信服务,这样我就不必同时加载它们并浪费资源(例如,如果用户有 10 个选项...? )。
我遇到的问题是在我的引导代码之外使用容器(我不希望我的代码依赖于容器)。我似乎找不到将容器用于延迟加载服务的方法(除非我手动创建所需的服务并手动执行所有 DI)。这是可以改变规则的情况还是有更好的方法?
有时,我发现自己处于仅在满足特定条件时才需要解决服务的情况。例如,用户可能选择发送电子邮件或短信通知。我想根据用户的选择延迟加载电子邮件或短信服务,这样我就不必同时加载它们并浪费资源(例如,如果用户有 10 个选项...? )。
我遇到的问题是在我的引导代码之外使用容器(我不希望我的代码依赖于容器)。我似乎找不到将容器用于延迟加载服务的方法(除非我手动创建所需的服务并手动执行所有 DI)。这是可以改变规则的情况还是有更好的方法?
如果您使用的是 Castle Windsor 3.0 或更新版本,您可以使用惰性解析。
有关详细信息,请参阅Windsor 3 中的新增功能。
注册过程有一点变化(必须注册新的组件加载器)。
之后,您只是像往常一样注册组件,但将依赖项解析为Lazy<T>
而不是T
. 除非您不访问.Value
的属性Lazy<T>
,否则不会解决依赖关系,因此您可以传递一些惰性评估的对象,并仅在需要时访问您需要的对象。
如果您对用户有更多选择,也许您应该考虑创建某种抽象工厂接口。然后,您将只注册并解析该工厂,工厂本身将创建适当的服务来发送通知(无论是邮件、短信还是任何其他选项)。工厂的实现可以手动编码,或者您可以用 Castle Windsor 编码(我认为是从 3.0 版开始)。
通常当我确实使用这样的工厂时,我会手动实现它并将容器作为它的依赖项传递,所以只有工厂实现依赖于我的容器。
只是一个简化的例子(基于 Marcin Deptuła 的回答)
// activate Lazy initialization feature for all Components
.Register(Component.For<ILazyComponentLoader>().ImplementedBy<LazyOfTComponentLoader>())
// register rest of component(s)
.Register(Component.For<IIssueRepository>().ImplementedBy<IssueRepository>())
. ....
懒惰地解决(属性注入)
public Lazy<IIssueRepository> IssueRepository { get; set; }
IssueRepository.Value.GetLastIssue();
解析正常(属性注入)
public IIssueRepository IssueRepository { get; set; }
IssueRepository.GetLastIssue();
通常,您可以使用Typed Factory Facility来做到这一点。
简而言之,当您解析使用这些服务的组件时,不是给它一个电子邮件或短信服务,而是给它一个可以创建它们的工厂(由您定义,不引用容器)
该设施将负责“实现”您的工厂(从您创建的界面),因此几乎没有什么可做的。