我正在尝试使用Ninject作为Windows服务的IoC框架。 我有以下类和接口:
装配核心:
public class Orchestrator : IOrchestrator
{
...
public Orchestrator(ITerminal terminal)
{
...
}
...
}
装配Vx520:
public class Vx520 : ITerminal
{
...
public Vx520(string comPort, int bauds, int dataBits, Parity parity, StopBits stopBits)
{
...
}
...
}
装配Vx580:
public class Vx580 : ITerminal
{
...
public Vx580(string ip, int port)
{
...
}
...
}
我的想法是使用ConfigurationSection
让用户配置他想要的终端数量和数量。例如,在以下配置中,我应该获得3个Orcestrator实例,一个带有Vx520终端,另外两个带有Vx580,每个都有自定义配置:
<Terminals>
<add Type="Vx520" ComPort="COM3" Bauds="9600" DataBits="8" Parity="None" StopBits="One" />
<add Type="Vx580" Ip="192.168.0.50" Port="33999"/>
<add Type="Vx580" Ip="192.168.0.51" Port="33999"/>
</Terminals>
我让配置部分正常工作,最终输出为IEnumerable<TerminalConfiguration>
。
有没有办法使用此配置列表动态解析Orchestrator
类的依赖项?
如果Ninject无法执行此操作,是否还有其他可以推荐我的IoC框架?
提前谢谢
答案 0 :(得分:1)
Ninject(或大多数甚至是所有DI容器)不能用于根据某些任意“外部”信息控制要实例化的对象数。 您可以做的是拥有多个绑定,如下所示:
IBindingRoot.Bind<IOrchestrator>().To<Orchestrator>();
IBindingRoot.Bind<IOrchestrator>().To<Orchestrator>();
IBindingRoot.Bind<IOrchestrator>().To<Orchestrator>();
然后注入它们(类型IEnumerable<IOrchestrator>
的ctor参数或通过IResolutionRoot.GetAll<IOrchestrator>()
检索它们。这将导致正好3个实例。
您还可以在绑定中放置条件的条件(上下文)绑定,例如:
IBindingRoot.Bind<ITerminal>().To<Vx520>()
.When(x => Config.Terminal.Type == "VX520");
IBindingRoot.Bind<ITerminal>().To<Vx580>()
.When(x => Config.Terminal.Type == "VX580");
当您注入ITerminal
/执行IResolutionRoot.Get<ITerminal>()
时,您将获得Vx520
或Vx580
(或缺少绑定异常!),具体取决于{{1 }}
现在,当然,您可以解析配置并相应地创建绑定:
Config.Terminal.Type
所以你会为foreach(ITerminalConfig config in Terminals)
{
IBindingRoot.Bind<IOrchestrator>().To<Orchestrator>()
.WithParameter(new ConstructorArgument("config", config, shouldInherit: true));
}
提供3个绑定,每个绑定都有一个IOrchestrator
来保存它的配置。由于ConstructorArgument
将ConstructorArgument
设置为true,因此shouldInherit
树中的类型可以注入,也可以注入条件。例如,您可以执行以下操作:
IOrchestrator
并将IBindingRoot.Bind<ITerminal>().To<Vx580>()
.When(ctx =>
{
ConstructorArgument configConstructorArgument =
ctx.Parameters
.OfType<ConstructorArgument>()
.Single(x => x.Name == "config");
var config = (ITerminalConfig)configConstructorArgument.GetValue(null, null);
return config.Type == "Vx520";
});
注入ITerminalConfig
(这就是你如何获得IP&amp; Port / comport&amp; baudrate,..设置)。
但说实话,不是创建多个Vx520
绑定,而是明确地完成创建不是更好吗?每个服务初始化程序/应用程序启动步骤使用Bind<IOrchestrator>().To<Orchestrator>()
创建实例?