Технологии

Кто расскажет про то как работает ninject, а именно аттрибут [inject] - вопрос №1072536

май 28, 2014 г.

  • Всего ответов: 1

  • Вилия - аватарка

    Вилия

    14-й в

    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
    {
        #regionVariable
        privateObservableCollection<IBook> _books;
        #endregion
     
        #regionConstructor
        publicHomeLibraryBookService()
        {
            _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 Methods
        publicvoidGetData(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контейнерам. Но если у Вас небольшое приложение, и Вам не нужно создавать много объектов через данный контейнер, то в плане простоты этот контейнер управления зависимостями -именно то, что нужно.

    ноябрь 2, 2016 г.

Похожие вопросы

Решено

Как принудительно удалить объект в C#?

август 3, 2012 г.

Технологии

Решено

Заполнение dataGridView данными из array

ноябрь 25, 2011 г.

Технологии