Создание экземпляра с использованием Ninject с дополнительными параметрами в конструкторе

Я решил начать использовать 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 ответ

Решение

With.ConstructorArgument существовал в 1.0 для этой цели. В 2.0 синтаксис немного изменился: - With.Parameters.ConstructorArgument с ninject 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 на лету [например, если объект кэшируется]

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

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

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

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

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

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

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

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

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