Ninject так же прост в изучении, как и Autofac. А благодаря множеству отдельных библиотек использование Ninjectпредоставляет все доступные на сегодняшний день возможности для управления зависимостями. В своей основе Ninjectочень прост для того, чтобы, потратив минимальный отрезок времени, его можно было использовать в Enterprise decision (бизнес-решениях). Хотя он не поддерживает interception, конфигурирования через xml(для этого нужно скачивать отдельно библиотеки, которых на момент написания статьи было около 30),asp.newmvc, MVC3, NLog, Glimpse и т.д. Чтобы продемонстрировать, как использовать данный IoCконтейнер, рассмотрим ту же реализацию электронной библиотеки, которая была использована для рассмотрения предыдущих IoCконтейнеров в предыдущих статьях (Unity, Autofac, CastleWindsorи StructureMap). Диаграмма классов приведена ниже.Для того, чтобы показать, как использовать контейнер Ninject, удалим в App.xamlстрочку для запуска формы в DependencyProperty(DP) -StartupUri. Для инициализации IoCконтейнера перед стартом программы необходимо перейти в классы App.xaml.csи переопределить метод OnStartup. Затем необходимо написать соответствующую реализацию.protectedoverridevoidOnStartup(StartupEventArgse){varkernel = newStandardKernel(); kernel.Bind<IBook>().To<LibraryBook>(); kernel.Bind<ILibraryBookService>().To<LibraryBookService>(); kernel.Bind<IVisitorRepository>().To<VisitorRepository>(); kernel.Bind<MainViewModel>().ToSelf(); kernel.Bind<MainWindow>().ToSelf();varmodel = kernel.Get<MainViewModel>();varview = kernel.Get<MainWindow>(); view.DataContext = model; view.Show();}Для простых программ достаточно всего две инструкции:Bind().To(); Bind().ToSelf(); Но для более сложных можно использовать дополнительные методы по выбору lifetimemanager(менеджер жизни объектов), инициализацию и использование конструктора на выбор, methodinjection(MI) и propertyinjection(PI) и многое другое. Ninjectтакже хорош тем, что он позволяет выполнять конфигурации в отдельных модулях. Посмотрим, насколько упростится наш пример с использованием модулей (NinjectModule). publicclassLibraryModule: NinjectModule{publicoverridevoidLoad() { Bind<IBook>().To<LibraryBook>(); Bind<ILibraryBookService>().To<LibraryBookService>(); Bind<IVisitorRepository>().To<VisitorRepository>(); Bind<MainViewModel>().ToSelf();Bind<MainWindow>().ToSelf(); }}Использование данного модуля:varkernel = newStandardKernel(newLibraryModule());varmodel = kernel.Get<MainViewModel>();varview = kernel.Get<MainWindow>();view.DataContext = model;view.Show();К сожалению, базового функционала, который идет в IoCконтейнере Ninject, может быть недостаточно для Вашего приложения, поэтому нужно будет загружать необходимые дополнения. Ninjectспроектирован по принципу: базовый функционал плюс дополнительные возможности, которые можно установить отдельно. Например, если Вы сторонник NHibernateи конфигурирования через файл конфигурации и не знакомы со Spring.Net(он отлично подходит для настроек NHibernate), посмотрите в сторону данного IoCконтейнера. Пример с NHibernateбыл просто приведен для сравнения, чтобы показать, как дополнительные библиотеки Ninjectпозволят ускорить процесс разработки.ConstrainResolutionОчень часто при разработке программного обеспечения приходится сталкиваться с тем, что от одного интерфейса наследуется несколько классов. А класс, который использует данный интерфейс, должен знать, с каким из вышеперечисленных вариантов его нужно использовать. Одним из самых простых вариантов решения данной проблемы является именованная привязка (Namedbinding). Продемонстрируем именованную привязку в электронной библиотеке, которая использовалась для примеров, добавив класс, который будет отвечать за работу с домашней коллекцией книг. Назовем этот класс HomeLibraryBookService, который наследуем от интерфейса ILibraryBookService. Ниже будет приведена тестовая реализация для демонстрации использования данного класса. В списке источников в конце статьи Вы можете скачать исходные коды к данной статье и ознакомится более подробно с использованием Ninject.publicclassHomeLibraryBookService: ILibraryBookService{ #regionVariableprivateObservableCollection<IBook> _books; #endregion #regionConstructorpublicHomeLibraryBookService() { _books = newObservableCollection<IBook>(); _books.Add(newLibraryBook{ Author = «Test1», Title = «Test Unity1», Count = 3, SN = «ISBN: 9781617291340», Year = newDateTime(2013, 9, 10) }); _books.Add(newLibraryBook{ Author = «Test2», Title = «Test Unity2», Count = 2, SN = «ISBN-10: 0201485672», Year = newDateTime(1999, 7, 8) }); } #endregion #regionPublic MethodspublicvoidGetData(Action<ObservableCollection<IBook>, Exception> callback) { callback(_books, null); }publicIBookFindBook(IBookfindBook) {if(findBook == null)returnnull;return_books.FirstOrDefault(book => book.Author == findBook.Author && book.Title == findBook.Title && book.SN == findBook.SN && book.Year == findBook.Year); }publicvoidCreateNewBook() { _books.Add(newLibraryBook{ Author = «UnityTest1», Title = «Test1», Count = 5, SN = «ISBN-10: 0735667454», Year = DateTime.Now }); }publicvoidRemoveBook(IBookbook) {if(book == null)return; _books.Remove(book);} #endregion}Интерфейс ILibraryBookServiceиспользуется в модели представления MainViewModel,которая отвечает за связывание моделей с представлением для проекта “Электронная библиотека”. Реализация представлена ниже. publicclassMainViewModel: NotifyModelBase {privatereadonlyILibraryBookService_libraryDataService;publicMainViewModel(ILibraryBookServicedataService) { _libraryDataService = dataService; _libraryDataService.GetData( (items, error) =>{ Books = items; }); }}С данного класса для был приведен только необходимый код для модифицированного примера использования. Посмотрим, как изменился класс LibraryModuleсо внесением именованной привязки.publicclassLibraryModule: NinjectModule{publicoverridevoidLoad() { Bind<IBook>().To<LibraryBook>(); Bind<ILibraryBookService>().To<HomeLibraryBookService>().Named(«HomeLibrary»); Bind<ILibraryBookService>().To<LibraryBookService>().Named(«Library»); Bind<IVisitorRepository>().To<VisitorRepository>(); Bind<MainViewModel>().ToSelf();Bind<MainWindow>().ToSelf(); }}К сожалению, сразу после внесения проект не запустится, так как нужно указать, какой класс будет использоваться при constructorinjectionв классе MainViewModel. Поэтому в данном классе изменим немного вызов конструктора.publicMainViewModel([Named(«Library»)]ILibraryBookServicedataService)В данном примере был рассмотрен один из самых простых способов решения ограничения по привязке. Другим способом является ограничения связывания с помощью использования ConstraintAttribute. Поскольку в примере с электронной библиотекой сложно представить, как использовать данный подход, возьмем пример, предоставленный разработчиками Ninject.// will work just as well without this line, but it's more correct and important for IntelliSense etc.[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)]publicclassSwimmer: ConstraintAttribute{publicboolMatches(IBindingMetadatametadata) {returnmetadata.Has(«CanSwim») && metadata.Get<bool>(«CanSwim»); }}classWarriorsModule: Ninject.Modules.NinjectModule{publicoverridevoidLoad() { Bind<IWarrior>().To<Ninja>(); Bind<IWarrior>().To<Samurai>().WithMetadata(«CanSwim», false); Bind<IWarrior>().To<SpecialNinja>().WithMetadata(«CanSwim», true); }}classAmphibiousAttack{publicAmphibiousAttack([Swimmer]IWarrior warrior){Assert.IsType<SpecialNinja>(warrior); }}ИтогиNinject-это мощный и одновременно легкий в использовании IoCконтейнер. По простоте использования, а также понятности apiэтот контейнер чем-то напоминает Autofac. Данный контейнер имеет очень мощную поддержку в онлайн-обществе. Пожалуй, единственным нюансом, который может смущать в данном IoCконтейнере, -это скорость его работы. Почему-то этот контейнер для управления зависимостями уступает по скорости всем описанным мной ранее IoCконтейнерам. Но если у Вас небольшое приложение, и Вам не нужно создавать много объектов через данный контейнер, то в плане простоты этот контейнер управления зависимостями -именно то, что нужно.