【发布时间】:2014-09-20 13:59:22
【问题描述】:
我正在构建一个 WPF(桌面)应用程序,使用依赖注入、一个 DI 容器和 Register-Resolve-Release pattern。我的应用程序还在启动期间从单独的程序集中加载插件,并且这些插件已在 DI 容器中注册。我在启动时在组合根中解析了我的整个对象图,但是,我在解析我的插件时遇到了一些问题,我想知道是否可以将 DI 容器注入工厂以解决未知问题类型?。
我的所有插件:
- 实现一个通用接口,
IPlugin - 需要是瞬态的(因为多个实例可以同时存在)
- 在初始化时依赖运行时值来配置它们
- 可能会或可能不会通过其构造函数注入其他依赖项
我已经开始实现PluginFactory 来在我需要插件时对其进行初始化,因为Mark Seemann says:“任何需要运行时值来构造特定依赖项的地方,抽象工厂是解决方案。”
但是,我不能只 new() 我工厂中的插件,因为我不知道它们的类型和依赖关系。
我想到了几个解决方案:
我可以将 DI 容器注入到
PluginFactory的构造函数中,在运行时解析插件并收工。但是,这违反了 RRR 模式。我可以通过
PluginFactory的构造函数注入IEnumerable<IPlugin> plugins。但是,这将违反临时要求,因为每个实例只有一个副本[*错误]。我可以通过在我的所有插件上实现ICloneable并在工厂中克隆它们来解决这个问题,但是,这既难以纠正依赖关系,又会使所有插件混乱。
[*Wrong] 编辑:注意,根据选择的答案,这是错误的!因此,选项 #2 是最佳选择,只要您将插件的生命周期注册为瞬态即可。
我可以将插件类型而不是实例注入
PluginFactory并使用Activator.CreateInstance<T>()创建实例。我什至可以为插件和pass parameters to the Activator 定义一个通用的构造函数签名,以使用依赖项来初始化它们。但是,这违反了我对插件具有不同依赖项的要求,并且还导致了constrained construction anti-pattern。最后,在 3 的基础上进行构建。我可以注入插件类型并使用反射来整理插件的依赖关系。然而,这听起来像是很多工作,让我想知道我是否正在尝试从 DI 容器构建或复制解析方法。后者是我绝对不想做或不想看到的重点。
所以,在我的选择中,我最喜欢#1,即使这违背了 RRR 模式。
实例化我的插件的最佳方式是什么(我倾向于#1)。我是否完全错过了一些替代方案?还是我可能误判了我的一些其他选择?
【问题讨论】:
-
“但是,这将违反临时要求,因为每个实例只有一个副本。”。这完全取决于您使用的 DI 库。在 Simple Injector
IEnumerable<T>中,依赖项真正作为流提供,这意味着每次迭代可枚举时都会要求容器解析该实例。这样可以保留插件的生活方式。 -
这很有趣。我这里假设太多了,容器显然比我聪明。您能否添加此评论作为答案?我觉得评论比您提供的其他答案更好地回答了我的真正问题:)
-
这取决于您选择的容器。您目前使用的是哪个库?
-
SimpleInjector :) 如果您提供一个简短的 sn-p 说明如何在注册后(使用 RegisterAll)设置各个插件的生命周期,那就太好了。
标签: c# plugins dependency-injection simple-injector di-containers