При применении зависимостей Инъекции и соблюдения требований Dependency Inversion Principle общий совет: to program to interfaces, not implementations. Именно поэтому большая часть времени вы увидите привязки, которые идут от абстракции к реализации:
Bind<IWarrior>().To<Samurai>();
Это означает, что компоненты будут принимать зависимость от IWarrior
во время компиляции, и мы впрыснуть Samurai
во время выполнения.
При определенных условиях, однако, имеет смысл отображать от конкретного компонента к себе. Другими словами, если «кто-то» запрашивает Samurai
, мы предоставляем его Samurai
.
Наиболее известный случай при разрешении типов корней. Типы корней - это вершина графика зависимости; корневые типы разрешаются непосредственно из контейнера. Все остальные типы являются прямыми или косвенными зависимостями корневого типа.
Часто вы обнаружите, что эти корневые типы разрешены конкретными типами и часто мы имеем дело с интерфейсом пользовательского интерфейса. Примерами таких являются веб-формы Page
s, MVC Controller
s, веб-API ApiController
s и т. Д.
Большинство контейнеров DI позволяют разрешать конкретные незарегистрированные типы в любом случае. Это может заставить вас поверить, что самообучение избыточно, но это не всегда так. Добавление такого привязки явно позволяет контейнеру узнать о существовании такой привязки. Это имеет преимущество при использовании диагностических возможностей контейнера (если имеется) для сканирования графов объектов для ошибок. В случае отсутствия такой функции обычно можно проводить итерацию известных регистраций и выполнять некоторую проверку внутри единичного теста. Для того чтобы такая проверка имела смысл при повторной регистрации контейнера, все корневые типы должны быть зарегистрированы в контейнере. В противном случае этот процесс проверки приведет к ложным отрицаниям.
Другая причина, по которой вы хотите рассказать контейнер DI о самообучении, заключается в том, что контейнер не разрешает разрешать незарегистрированные типы или когда вам нужен тип, который должен быть зарегистрирован в другом стиле жизни, чем стиль жизни по умолчанию в контейнере. В большинстве контейнеров вы получите экземпляр Transient, если тип не зарегистрирован.
Это просто делает фреймворк осведомленным об объекте, который будет разрешен. Например, «Bind() .ToSelf() .InSingletonScope();' позволяет контейнеру знать, что тип должен быть разрешен как одноэлементный. В целом это всего лишь часть регистрации типов с контейнером. –
Nkosi
Но зачем это нужно решать? если мы передаем экземпляр в конструктор, я не вижу необходимости его разрешать. Также используется '.InSingletonScope()', поэтому нам не нужно самостоятельно реализовать шаблон singleton? – oflad
, потому что контейнер - это экземпляр экземпляров экземпляров, и ему нужно знать, какие типы он может создать и как обрабатывать или обрабатывать их.Вы понимаете принцип инверсии зависимостей? вся цель контейнера состоит в том, чтобы не делать это самостоятельно – Nkosi