2014-11-17 5 views
2

Я пытаюсь использовать Ninject в качестве моей инфраструктуры IoC для службы Windows. У меня есть следующие классы и интерфейсы:Устранение различных экземпляров на основе конфигурации

Ассамблея Core:

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

Какой из них вы хотите вставить в «Orchestrator»? На основании чего вы принимаете решение? –

+0

@YuvalItzchakov На основании списка «TerminalConfiguration». Предположим, что у меня есть 3 элемента в этом списке, затем я хочу, чтобы 3 'Orchestrator' каждый из них имел один из терминалов, основанный на поле« Тип »конфигурации –

ответ

1

Ninject (или большинство или даже все контейнеры DI для этого вещества) не могут быть использованы для контроля количества объектов для создания экземпляра на основе некоторой произвольной «внешней» информации. Что вы можете сделать, это иметь несколько привязок, например, так:

IBindingRoot.Bind<IOrchestrator>().To<Orchestrator>(); 
IBindingRoot.Bind<IOrchestrator>().To<Orchestrator>(); 
IBindingRoot.Bind<IOrchestrator>().To<Orchestrator>(); 

, а затем вводят их (CTOR аргумент типа IEnumerable<IOrchestrator> или получить их 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"); 

и когда вы вводите ITerminalIResolutionRoot.Get<ITerminal>() вы получите Vx520 или Vx580 (или недостающий обязательные исключительные возможности on!) в зависимости от значения Config.Terminal.Type.

Теперь, конечно, можно разобрать конфигурационный файл и создать привязки соответственно:

foreach(ITerminalConfig config in Terminals) 
{ 
    IBindingRoot.Bind<IOrchestrator>().To<Orchestrator>() 
     .WithParameter(new ConstructorArgument("config", config, shouldInherit: true)); 
} 

Таким образом, вы бы 3 привязок для IOrchestrator, каждый с ConstructorArgument который держит его конфигурация. Поскольку ConstructorArgument имеет значение shouldInherit, значение true, типы вниз по дереву 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 впрыскивается в Vx520 (это, как вы бы получить IP & Port/ComPort & BaudRate, .. настройки).


Но, честно говоря, вместо того чтобы создавать несколько Bind<IOrchestrator>().To<Orchestrator>() привязок, не было бы лучше, чтобы создание сделано явно? На какой-то шаг инициализации/запуска службы, который использует IOrchestratorFactory для создания экземпляров?

+0

Спасибо за ваш ответ. Я решил выбрать, какой терминал должен вставлять ваш последний фрагмент кода, и разрешить «Orchestrator's» с конфигурацией. Terminals.Select (config => kernel.Get (new ConstructorArgument («config», config , true))) ' –

Смежные вопросы