я могу описать только то, что мы придумали. Мы заимствовали синтаксис использования и такие возможности из различных онлайновых библиотек, но этот код - все наше.
В принципе, у нас есть то, что мы называем ServiceContainer, объектом. Всегда есть глобальный экземпляр, однострочный экземпляр, если хотите, статический и, следовательно, в веб-приложении, который используется всеми пользователями в приложении.
A ServiceContainer содержит правила. Правила говорят такие вещи, как Если кто-то спрашивает объект типа XYZ, вот как вы собираетесь предоставить им его.
Например, правило может заключаться в том, что для того, чтобы некоторый код мог получить объект, реализующий IDbConnection, контейнер создавал, настраивал и возвращал новый объект SqlConnection.
Этот код, таким образом, не знает и не заботится о том, что он использует объект SqlConnection, а не объект OleDbConnection.
Написав это, я понимаю, что это не очень хороший пример, потому что в конечном итоге вы спрашиваете соединение для объектов команды, а синтаксис SQL, который вы передаете этому объекту, должен быть адаптирован к типу соединения. Но если мы можем игнорировать этот момент прямо сейчас, код не будет знать, что он подключается к SQL Server, он просто знает, что у него есть объект соединения.
Теперь необходимо указать код, который должен использовать контейнер, который он должен использовать, и, следовательно, правила.Это означает, что с точки зрения модульного тестирования я мог бы создать новый экземпляр ServiceContainer, записать в него новые правила для тестирования и попросить код выполнить его. В конечном итоге код хотел бы выполнить какой-то SQl (в данном случае), а вместо того, чтобы разговаривать с реальной базой данных, он будет вызывать мою тестовую реализацию IDbConnection и IDbCommand и, таким образом, дать мне возможность проверить, что все работает.
Что еще более важно, это дает мне возможность вернуть обратно известные фиктивные данные, соответствующие тесту, без необходимости составлять полную базу данных.
Теперь для впрыска часть, в нашем случае мы можем спросить контейнер, чтобы предоставить нам объекты, которые должны быть построены, которые полагаются на другие объекты.
Например, у нас есть интерфейс IDataAccessLayer и реализация MSSQLDataAccessLayer.
Хотя интерфейс не дает нам какого-либо внешнего признака того, что он выполняет любое ведение журнала, фактическая реализация здесь должна иметь место для регистрации всего SQL, который он выполняет. Таким образом, конструктор класса может выглядеть следующим образом:
public MSSQLDataAccessLayer(ILogger logger) { ... }
В объекте ServiceContainer мы зарегистрировали следующие правила (это наш синтаксис, вы не найдете, что где-нибудь еще, но это должно быть легко достаточно следовать):
ServiceContainer.Global.RegisterFactory<ILogger, FileLogger>()
.FactoryScoped()
.WithParameters(
new Parameter("directory", @"C:\Temp")
);
ServiceContainer.Global.RegisterFactory<IDataAccessLayer, MSSQLDataAccessLayer>()
.FactoryScoped();
FactoryScoped означает, что каждый раз, когда я спрашиваю контейнер для объекта, я получаю новую.
правила, если я их пишу на английском языке, являются, как это:
- Если кто-то нуждается в реализации, если ILogger, построить новый объект FileLogger и взять конструктор, который требует параметр «каталог», и использовать этот конструктор при переходе в «C: \ Temp» в качестве аргумента
- Если кому-то нужна реализация IDataAccessLayer, построить новый MSSQLDataAccessLayer
Обратите внимание, что я уже говорил о том, что конструктор MSSQLDataAccessLayer принимает ILogger, но я не указал здесь никаких параметров? Это дает мне следующий код, чтобы разжиться объект уровня доступа:
IDataAccessLayer dal = ServiceContainer.Global.Resolve<IDataAccessLayer>();
Что происходит сейчас в том, что объект контейнера выясняет, что объект MSSQLDataAccessLayer, и что у него есть конструктор. Этот конструктор требует объекта ILogger, но вот, контейнер знает, как его создать. Таким образом, контейнер создаст новый объект FileLogger и передаст его конструктору объекта MSSQLDataAccessLayer.
Конфигурация большинства зависимостей приложений может быть выполнена однажды, где-то в центре и выполняется во время запуска, в то время как остальная часть кода блаженно не осознает всю магию, происходящую здесь.
Для тестирования модулей я могу переписать правила, чтобы предоставить свой собственный объект фиктивного регистратора, который просто хранит зарегистрированный текст в памяти, что позволяет мне легко проверить, что то, что я ожидал, зарегистрировал код в журнале, после этого читать в файле.
правило дает нам много энергии о том, как на самом деле предоставить экземпляры объектов:
- От делегата/методы, что означает, что мы можем сделать все волшебство построения зависимых объектов себя, если мы хотим
- Автоматически из конструктора (либо автоматически выясняется, какой из них использовать, либо мы можем предоставить достаточное количество фиктивных параметров по именам/типам для их выбора)
- Или мы можем предоставить существующий экземпляр контейнеру (это будет сортировать- быть похожим на одноэлементный)
Мы рассмотрели autofac перед тем, как придумать свои собственные, в основном мы просто посмотрели на вики, где показаны примеры синтаксиса вызова, а затем сели и написали нашу собственную систему, которая сделала то, что нам нужно.
Благодарим за информацию. Я на самом деле ищут ресурсы, которые очень полны с точки зрения обучения концепциям и демонстрации реализации. В вашем ответе есть много ответа. – 2008-11-19 17:19:02