#c# #dependency-injection #inversion-of-control
#c# #внедрение зависимостей #инверсия управления
Вопрос:
Позвольте мне иметь два очень простых объекта, таких как:
public class View
{
public View(Controller controller)
{
// Use the model exposed by the controller here
}
}
public class Controller
{
private readonly IView view;
public Controller()
{
this.view = new View(this);
}
public Controller(View v)
{
this.view = v;
}
}
Позже я решаю внедрить объект View в контроллер через DI, но там у меня циклическая зависимость (т. Е. Я не могу использовать var ctrl = new Controller(new View(ctrl));
). Как бы вы поступили с внедрением зависимости в этом случае?
Комментарии:
1. Собираетесь ли вы иметь несколько представлений для одного контроллера?
2. Нет, только один. Однако в этом случае я пытаюсь избежать внедрения свойств.
3. Итак, зачем добавлять разрешение DI для просмотра? Между представлением и контроллером будет соотношение 1: 1. Извините, я не вижу в этом смысла.
4. Извините, теперь я понял, что вы имели в виду (я думал, вы спрашивали об одном экземпляре). Да, будет несколько представлений (gui, cli и т.д.)
5. Затем я предлагаю использовать ctor like
Controller(IView view)
, удалитьcontroller
параметр изView
и добавить свойство для установкиController
экземпляраView
.
Ответ №1:
Наиболее распространенным решением является использование свойства зависимости для решения циклических зависимостей. т.Е. Создайте новое свойство в одном из классов и позвольте контейнеру IoC назначить его.
Если вы используете Unity, вы должны добавить [Dependency]
к этому свойству.
Примечание: представление не должно иметь зависимости от контроллера. Он вообще не должен знать об этом.
Обновление в ответ на комментарий
Вы не можете. Это проблема с циклическими зависимостями. Единственное другое решение — использовать композицию. Это означает выделение общей функциональности в отдельный класс и включение ее как в контроллер, так и в представление.
Комментарии:
1. Да, на самом деле представление использует только модель (для привязки данных), предоставляемую контроллером, в данном случае постарался быть кратким. Кстати, я пытаюсь избежать внедрения свойств (поскольку зависимости имеют решающее значение для функциональности класса).
2. да, вы правы в этом, похоже, мне придется использовать prop-inj. или другое экзотическое решение.
3. Ваш собственный ответ — это вариант шаблона поиска служб. Вы также можете создать a
ViewFactory
, который принимает контроллер в качестве параметра и принимает его в качестве параметра конструктора в контроллере.4. Спасибо за отличную
ViewFactory
идею, я должен был подумать об этом раньше.. продвигаемся вперед с заводской реализацией.
Ответ №2:
Я действительно нашел хорошее решение, используя Ninject.
public class Controller
{
private readonly View view;
public Controller(ViewModule viewModule)
{
using (IKernel kernel = new StandardKernel(viewModule))
{
this.view = kernel.Get<View>(new ConstructorArgument("controller", this);
}
}
}
Где ViewModule является предварительно настроенным модулем Ninject для разрешения конкретной зависимости представления (GUI, CLI и т. Д.). Небольшая проблема здесь заключается в том, что теперь я зависим от конкретной платформы DI.
Ответ №3:
Вы вообще не сможете этого сделать с помощью constructor-injection, если вы измените конструктор контроллера на
public Controller(IView view)
в каком порядке вы бы создали два объекта?
Для представления требуется экземпляр контроллера, а контроллеру требуется представление.
Тем не менее, вы можете сделать свойство IView контроллера общедоступным и установить свойство после создания (некоторые DI-контейнеры могут сделать это для вас автоматически при установке правильного атрибута).