Используя Ninject, если я создаю собственного провайдера, я должен обеспечить один экземпляр или использовать атрибут SingleInstance? - PullRequest
6 голосов
/ 24 февраля 2010

Я надеюсь, что или Питер, или Рубен увидят этот вопрос, потому что они, похоже, обращаются к парням по поводу Ninject. Мне нужно было создать собственный поставщик, потому что у меня есть класс, который принимает 4 аргумента. Два могут быть введены, потому что они являются типами, но два других являются параметрами конфигурации и являются целыми числами. Они относятся к тайм-аутам в миллисекундах.

[SingleInstance]
MyClass
{
    ISomething something;
    IOther other;
    int timeout;
    int delay;

    [Inject]
    MyClass(ISomething something, IOther other, int timeout, int delay)
    {
        this.something = something;
        this.other = other;
        this.timeout = timeout;
        this.delay = delay;
    }
}    

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

Пара дополнительных очков:

  1. Я знаю, что могу использовать инъекцию на параметры. Но это создает обманчивый API. Объекты должны быть вернулся в состояние готовности к использованию и без этих 4 аргументов это не так готов к использованию.
  2. Применяется тот же аргумент к методу инъекции.

Итак, мои последние вопросы:

  • Значит ли это, что я контролирую повторное обеспечение единственного экземпляра или Ninject по-прежнему позаботится об этом через атрибут [SingleInstance]?
  • Должен ли я просто вернуться на завод, который у меня был? Что я получу от использования Ninject в этом случае?

ОБНОВЛЕНИЕ: Пример кода по запросу

Тогда мой провайдер, я полагаю, хотел бы что-то вроде этого:

class MyClassProvider : SimpleProvider<MyClass> {
protected override MyClass CreateInstance(IContext context) {
    int timeout= ConfigurationManager.AppSettings.Get("timeout");
    int delay= ConfiguraionManager.AppSettings.Get("delay");
    ISomething something = new SomethingImpl();
    IOther other = new OtherImpl();
    MyClass newOne = New MyClass(something, other, timeout, delay);
    }
}

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

class MyClassProvider : SimpleProvider<MyClass> {

    protected static readonly MyClass myClassInstance;
    private static object locker = new object();

    protected override MyClass CreateInstance(IContext context) {
        if (myClassInstance == null) 
        {
            lock (locker)
            {
                int timeout = ConfigurationManager.AppSettings.Get("timeout");
                int delay = ConfiguraionManager.AppSettings.Get("delay ");
                ISomething something = new SomethingImpl();
                IOther other = new OtherImpl();
                MyClass newOne = New MyClass(something, other, timeout, delay );
            }
            return MyClassInstance
        }
        return myClassInstance
    }
}

Есть что-то, чего мне не хватает?

Ответы [ 2 ]

3 голосов
/ 26 февраля 2010

У вас, ребята, довольно неплохая беседа, но я подумал, что добавлю ответ, чтобы прояснить ситуацию на основе исходного вопроса.

Короткий ответ заключается в том, что Ninject по-прежнему будет гарантировать, что у вас есть один экземпляр объекта, если вы укажите .Using<SingletonBehavior> в своем операторе связывания, независимо от механизма активации - т.е. вы не обойдете механизмы Ninject, обеспечивающие один экземпляр объекта создается при использовании вашего собственного провайдера с использованием синтаксиса .ToProvider или, в этом случае, синтаксиса .ToMethod.

Вы должны просто написать своему поставщику, чтобы он предоставил экземпляры объекта - никакая другая семантика не навязывается поставщику. Таким образом, все типичные сгущения, необходимые для создания одноэлементных экземпляров, как вы указали в примере выше, не требуются.

Как пример, ваш провайдер становится намного проще; хотя я добавил разрешение ISomething и IOther с использованием ядра Ninject к вашему исходному примеру:

class MyClassProvider : SimpleProvider<MyClass> {

  protected override MyClass CreateInstance(IContext context) {
    int timeout = ConfigurationManager.AppSettings.Get("timeout");
    int delay = ConfiguraionManager.AppSettings.Get("delay ");
    ISomething something = context.Kernel.Get<ISomething>();
    IOther other = context.Kernel.Get<IOther>();
    return new MyClass(something, other, timeout, delay );
  }
}

Ваше обязательное утверждение в вашем модуле Ninject будет выглядеть так:

public class MyModule : StandardModule {
  public override void Load() {

    Bind<IMyClass>()
      .ToProvider<MyClassProvider>()
      .Using<SingletonBehavior>();
  }
}

При использовании SingletonBehavior Ninject по-прежнему предоставит вам только один экземпляр MyClass, даже если вы используете своего собственного провайдера.

Это довольно легко проверить. Вы можете добавить свойство DateTime к своему классу, установить его в конструкторе DateTime.Now и проверить объекты, возвращенные множественными вызовами Get () - все они будут иметь одинаковое время, даже если вы создали класс в своем провайдере , Затем измените Using<SingletonBehavior> на Using<TransientBehavior> и наблюдайте разницу. Каждый раз вы будете получать новый, созданный вашим провайдером.

Надеюсь, что эта помощь - кстати, не уверен, что я тот Питер, о котором вы говорили, но если это так, я польщен!

1 голос
/ 25 февраля 2010

Если честно, у меня возникают проблемы с пониманием вашего вопроса - возможно, поможет пример кода, как вы его создадите (хотя ваш вопрос, как правило, хорошо сформулирован). Но вот удар.

Не уверен, что вы подразумеваете под SingleInstance - откуда это? (Я действительно не знал о SingletonAttribute в v1, но вижу, что это не в 2.0 Core). Хотя в некоторых случаях это имеет смысл, я бы определенно не использовал атрибуты поведения в классах в качестве подхода по умолчанию (т. Е. Вместо этого поместил бы его в определения привязки).

Я бы все же попытался использовать провайдера (или перегрузку Bind<T>.To* с лямбда-выражением как способ написать фабрику в меньшем количестве кода), тем более что слой поведения экземпляра можно использовать поверх него, и вы Вы будете получать все ваши объекты таким же образом, и это хорошо.

Еще одно предложение, которое я хотел бы сделать, заключается в том, что ваши параметры облысения и задержки могут быть сделаны первоклассными гражданами вашего DI-дерева, например, IConnectivityPolicy вещь, которая может использоваться в нескольких классах.

...