Создание экземпляра с использованием Ninject с дополнительными параметрами в конструкторе - PullRequest
63 голосов
/ 09 февраля 2010

Я решил начать использовать Ninject и столкнулся с проблемой. Скажем, у меня есть следующий сценарий. У меня есть IService интерфейс и 2 класса, реализующие этот интерфейс. А также у меня есть класс, в котором есть конструктор, получающий IService, и int . Как я могу создать экземпляр этого класса с помощью Ninject (я не хочу зашивать этот int, я хочу передавать его каждый раз, когда получаю экземпляр)?

Вот код, иллюстрирующий ситуацию:

interface IService
{
    void Func();
}

class StandardService : IService
{
    public void Func()
    {
        Console.WriteLine("Standard");
    }
}

class AlternativeService : IService
{
    public void Func()
    {
        Console.WriteLine("Alternative");
    }
}


class MyClass
{
    public MyClass(IService service, int i)
    {
        this.service = service;
    }

    public void Func()
    {
        service.Func();
    }

    IService service = null;
}
class Program
{
    static void Main(string[] args)
    {
        IKernel kernel = new StandardKernel(new InlineModule(
            x => x.Bind<IService>().To<AlternativeService>(),
            x => x.Bind<MyClass>().ToSelf()));

        IService service = kernel.Get<IService>();

        MyClass m = kernel.Get<MyClass>();
        m.Func();
    }
}

1 Ответ

93 голосов
/ 09 февраля 2010

With.ConstructorArgument существовал в 1.0 для этой цели. В 2.0 синтаксис немного изменился: С.Параметры.КонструкторАргмент с нинъектом 2.0

См. Добавление значения во внедренную зависимость для получения более подробной информации и примеров того, как использовать контекст, поставщиков и аргументы для более правильной передачи подобных вещей.

РЕДАКТИРОВАТЬ: Поскольку Стивен решил притворяться, что мой комментарий не имеет значения, я лучше поясню, что я говорю, с некоторыми примерами (для 2.0):

MyClass m = kernel.Get<MyClass>( new ConstructorArgument( "i", 2) );

, что, на мой взгляд, очень ясно и точно говорит о том, что происходит.

Если вы находитесь в состоянии, когда вы можете определить параметр более глобально, вы можете зарегистрировать поставщика и сделать это следующим образом:

class MyClassProvider : SimpleProvider<MyClass>
{
    protected override MyClass CreateInstance( IContext context )
    {
        return new MyClass( context.Kernel.Get<IService>(), CalculateINow() );
    }
}

И зарегистрируйте это так:

x => x.Bind<MyClass>().ToProvider( new MyClassProvider() )

NB. Бит CalculateINow() - это то место, куда вы вставили бы свою логику, как в первом ответе.

Или сделать его более сложным, например:

class MyClassProviderCustom : SimpleProvider<MyClass>
{
    readonly Func<int> _calculateINow;
    public MyClassProviderCustom( Func<int> calculateINow )
    {
        _calculateINow = calculateINow;
    }

    protected override MyClass CreateInstance( IContext context )
    {
        return new MyClass( context.Kernel.Get<IService>(), _calculateINow() );
    }
}

Который вы бы зарегистрировали так:

x => x.Bind<MyClass>().ToProvider( new MyClassProviderCustom( (  ) => new Random( ).Next( 9 ) ) )

ОБНОВЛЕНИЕ: в расширении Ninject.Extensions.Factory воплощены более новые механизмы, которые демонстрируют значительно улучшенные шаблоны с меньшим количеством шаблонов, чем указано выше, см .: https://github.com/ninject/ninject.extensions.factory/wiki

Как указывалось ранее, если вам нужно каждый раз передавать разные параметры и у вас есть несколько уровней в графе зависимостей, вам может потребоваться сделать что-то вроде этого .

Последнее соображение заключается в том, что, поскольку вы не указали Using<Behavior>, он будет по умолчанию установлен по умолчанию, как указано / задано по умолчанию в опциях для ядра (TransientBehavior в примере), что может привести к тому, что Фабрика вычисляет i на лету [например, если объект кэшируется]

Теперь, чтобы прояснить некоторые другие моменты в комментариях, которые FUDS и замаскированы. Некоторые важные вещи, которые следует учитывать при использовании DI, будь то Ninject или что-то еще:

  1. Сделайте как можно больше, используя инжектор конструктора, так что вам не нужно использовать специфичные для контейнера атрибуты и приемы. Есть хорошая запись в блоге под названием Ваш контейнер IoC показывает .

  2. Сведите к минимуму код, идущий к контейнеру и запрашивающий материал - в противном случае ваш код связан с a) конкретным контейнером (который может свернуть CSL) b) способом, которым выложен весь ваш проект. В этом блоге есть хорошие сообщения о том, что CSL не делает то, что вы думаете. Эта общая тема называется Расположение службы по сравнению с внедрением зависимости . ОБНОВЛЕНИЕ: См. http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx для подробного и полного обоснования.

  3. Минимизация использования статики и синглетонов

  4. Не думайте, что существует только один [глобальный] контейнер, и что можно просто требовать его всякий раз, когда вам это нужно, например, в симпатичной глобальной переменной. Правильное использование нескольких модулей и Bind.ToProvider() дает вам структуру для управления этим. Таким образом, каждая отдельная подсистема может работать самостоятельно, и у вас не будет компонентов низкого уровня, привязанных к компонентам верхнего уровня и т. Д.

Если кто-то захочет заполнить ссылки на блоги, на которые я ссылаюсь, я был бы признателен (хотя они все уже связаны с другими постами на SO, так что все это просто дублирование пользовательского интерфейса) с целью избежать путаницы с вводящим в заблуждение ответом.)

Теперь, если бы только Джоэл смог войти и действительно объяснил мне, какой хороший синтаксис и / или правильный способ сделать это!

ОБНОВЛЕНИЕ: Хотя этот ответ явно полезен из числа набранных голосов, я хотел бы дать следующие рекомендации:

  • Вышеупомянутое выглядит немного устаревшим и, честно говоря, отражает много неполного мышления, которое почти смущает после прочтения Внедрение зависимостей в .net - Беги и покупай сейчас - это не только DI первая половина - это полное рассмотрение всех архитектурных проблем, связанных с ним, от человека, который слишком много времени провел здесь, висящий вокруг тега внедрения зависимости.
  • Прочитайте Отметьте самые популярные посты здесь, на SO, прямо сейчас - вы узнаете ценные приемы у каждого
...