根据配置解析不同的实例

时间:2014-11-17 19:06:10

标签: c# ninject ioc-container

我正在尝试使用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框架?

提前谢谢

1 个答案:

答案 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>()时,您将获得Vx520Vx580(或缺少绑定异常!),具体取决于{{1 }}

现在,当然,您可以解析配置并相应地创建绑定:

Config.Terminal.Type

所以你会为foreach(ITerminalConfig config in Terminals) { IBindingRoot.Bind<IOrchestrator>().To<Orchestrator>() .WithParameter(new ConstructorArgument("config", config, shouldInherit: true)); } 提供3个绑定,每个绑定都有一个IOrchestrator来保存它的配置。由于ConstructorArgumentConstructorArgument设置为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>()创建实例?