2010-03-07 3 views
6

Рассмотрим следующий пример:Ninject 2.0 - привязка к объекту, который использует один и тот же интерфейс более одного раза?

public Something(IInterface concreteObjectOne, IInterface concreteObjectTwo) 
    { 
     this.concreteObjectOne = concreteObjectOne; 
     this.concreteObjectTwo = concreteObjectTwo; 
    } 

Как установить установить этот тип связывания с Ninject? Я бы попробовал Googling этот термин, но, поскольку я не уверен, что это называется, я не могу, и я не могу найти что-либо в Wiki об этом.

Edit:

Я считаю, что это называется конвенции на основе связывания, как описано here. Однако эта документация для версий 1.0 и 2.0 не имеет метода Only. Я бы хотел, чтобы это было достигнуто без атрибутов - с использованием соглашения имен или чего-то подобного.

ответ

9

В дополнение к использованию метода «Только» в статье предлагается другое решение путем указания различных атрибутов для введенных объектов.

Пример:

public class ObjectOneAttribute : Attribute 
{ 

} 
public class ObjectTwoAttribute : Attribute 
{ 

} 

Тогда

public Something([ObjectOneAttribute] IInterface concreteObjectOne, [ObjectTwoAttribute] IInterface concreteObjectTwo) 
    { 
     this.concreteObjectOne = concreteObjectOne; 
     this.concreteObjectTwo = concreteObjectTwo; 
    } 

И когда вы хотите связать интерфейс к правильному конкретному объекту, используйте метод "WhereTargetHas":

Bind<IInterface>().To<YourConcreteTypeOne>().WhereTargetHas<ObjectOneAttribute>(); 
Bind<IInterface>().To<YourConcreteTypeTwo>().WhereTargetHas<ObjectTwoAttribute>(); 

Обновление: Solution без использования атрибутов:
Используйте метод "Когда":

Bind<IInterface>().To<YourConcreteTypeOne>().When(r => r.Target.Name == "concreteObjectOne"); 
Bind<IInterface>().To<YourConcreteTypeTwo>().When(r => r.Target.Name == "concreteObjectTwo") 

;

+0

Я бы предпочел не добавлять атрибуты. В конце статьи показано, как использовать соглашение, например. параметр называется X. Именно это я и делаю. – Finglas

+0

@Finglas Я обновил другое решение – 2010-03-07 13:31:10

+0

Отлично. Я был близок, когда я играл, чтобы заставить это работать, но ты на месте. У меня нет ничего против атрибутов, кстати, я просто нахожу в этом сценарии, что это расточительно. Этот тип конфигурации не распространен в моей базе кода, поэтому использование метода «Когда» намного приятнее. Приветствия. – Finglas

5

Если мне может быть позволено предложить какое-то общее, а не конкретное для Ninject, руководство по этому вопросу, я бы предложил вам немного пересмотреть свой дизайн. Текущий конструктор vague, потому что он не дает никаких указаний о том, какая реализация IInterface, которая идет туда, - я понимаю, что это всего лишь макет вашего реального API, и хотя реальный API может предложить большую помощь человеческому разработчику в форма точно названных параметров, машина, подобная контейнеру DI, не может вывести правильное использование.

Многие контейнеры DI предлагают способ устранения такой неопределенности, например, путем предоставления атрибутов, которые вы можете использовать для связывания имен (метаданных) с каждой зависимостью. AFAIR, Ninject имеет Inject атрибуты ...

Однако рассмотреть несколько альтернатив:

Первый вариант заключается в инкапсуляции два одинаковых экземпляра интерфейса в параметров объекта, как это:

public interface IParameterObject 
{ 
    IInterface ObjectOne { get; } 

    IInterface ObjectTwo { get; } 
} 

Теперь вы можете изменить конструктор, чтобы взять экземпляр IParameterObject вместо двух экземпляров интерфейса.

public Something(IParameterObject po) 
{ 
    this.concreteObjectOne = po.ObjectOne; 
    this.concreteObjectTwo = po.ObjectTwo; 
} 

Это означает, что вы можете нажать конфигурацию IParameterObject к Composition Root.

Другой альтернативой является обдумывать, имеет ли смысл рассмотреть случай с двумя экземплярами как просто частный случай более общей конструкции, которая принимает любое количество экземпляров. Это может быть не всегда так, но если это так, вы можете изменить конструктор для этого:

public Something(IEnumerable<IInterface> objects) 

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

+0

@Mark. Вы ответили вчера (еще раз спасибо) переместили меня на использование фабрики, чтобы использовать шаблон разработки стратегии для моих подключаемых алгоритмов. Заводы, о которых идет речь, теперь берут два конкретных объекта, но поскольку я использую шаблон стратегии, они оба имеют один и тот же интерфейс. Обычно без IOC я бы написал такой код и вручную подключил зависимости. Это также упрощает модульное тестирование. Хотя то, что вы предложили, будет работать, я как-то чувствую, что это не важно. С 2.0 я просто не могу найти правильный способ сделать что-либо, кроме простого связывания. – Finglas

+0

Достаточно честно - рад, что вы нашли решение :) –