SimpleServiceLocator: Почему автоматическое внедрение конструктора не поддерживается для синглетонов? - PullRequest
1 голос
/ 05 сентября 2010

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

Почему SimpleServiceLocator спроектирован таким образом?

Разве синглоны не должны быть такими же, как обычныекроме того, что при первом запросе экземпляра этот экземпляр сохраняется и используется повторно вместо того, чтобы каждый раз создавался новый?Почему SimpleServiceLocator требует, чтобы экземпляр предоставлялся во время процесса регистрации, а не просто позволял создавать и сохранять экземпляр при первом запросе?

Я понял, что смысл SimpleServiceLocator состоит в том, чтобы не иметь много колоколов исвистит и очень прост в использовании для новичков, но кажется, что он просто спроектирован неправильно, и что метод регистрации синглтона должен быть идентичен методу регистрации обычного экземпляра, за исключением того, что имя метода должно быть RegisterSingle<T>() вместоRegister<T>().Есть ли причина для более сложного (и, казалось бы, менее удобного) дизайна, который я просто не получаю?

Между тем, есть ли другой (предпочтительно бесплатный) контейнер IOC, который я могу использовать, который позволяет мне регистрировать объекты в коде аналогичнов SimpleServiceLocator, но разрешает ли автоматическую инжекцию конструктора для синглетонов (или, по крайней мере, позволяет автоматическую инжекцию конструктора для зависимостей синглтона)?

Ответы [ 2 ]

2 голосов
/ 05 сентября 2010

Метод RegisterSingle<T> - это просто причудливый вспомогательный метод, облегчающий жизнь. То, что вы можете сделать с RegisterSingle<T>, также можно сделать с помощью метода Register<T>. На сайте приведены примеры этого . Вы можете зарегистрировать один экземпляр, используя метод Register<T> следующим образом (он использует замыкание):

var weapon = new Katana();
container.Register<IWeapon>(() => weapon);

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

[ThreadStatic]
private static IWeapon weapon;

container.Register<IWeapon>(
    () => return weapon ?? (weapon = new Katana()));

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

private static IWeapon weapon;

container.Register<IWeapon>(
    () => weapon ?? (weapon = container.GetInstance<Katana>()));

Хитрость здесь в том, чтобы сохранить экземпляр в статической переменной (так же, как со статическим потоком), но теперь вам не следует создавать экземпляр самостоятельно, new его задействовав, но вы делегируете создание в Simple Service Локатор. Это работает, потому что, как вы знаете, SimpleServiceLocator будет выполнять автоматическое внедрение конструктора при запросе конкретного типа.

Я должен признать, что это позор, что нам нужно сделать этот обман. Было бы хорошо, если бы библиотека могла сделать это за нас. Например, я могу представить добавляемую перегрузку RegisterSingle<T>, которая позволяет нам делать следующее:

container.RegisterSingle<IWeapon>(
    () => container.GetInstance<Katana>());

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

Обновление:

С версии 0.14 мы можем сделать следующее:

container.RegisterSingle<IWeapon, Katana>();

Это не станет легче, чем это.

Приветствия

0 голосов
/ 05 сентября 2010

Типичная одноэлементная реализация имеет конструктор private, поэтому контейнер не может «увидеть» его, вызвать его или обнаружить зависимости.

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

Это не то, что означает синглтон. Хотя контейнер возвращает тот же экземпляр, ничто не мешает вам создать экземпляр в коде, используя new.

Синглтон, с другой стороны, может быть создан только один раз из любого источника (один раз для потока в некоторых реализациях). Он не предоставляет открытый конструктор, а статический метод, такой как:

public class MySingleton
{
    // note: not a thread-safe implementation
    static MySingleton instance;
    static DependencyThing thing;

    private MySingleton(DependencyThing thing)
    {
        MySingleton.thing = thing;
    }

    public static MySingleton GetMySingleton(DependencyThing thing)
    {
        if(instance == null) instance = new MySingleton(thing);
        return instance;
    }
}

Как видите, вы не можете позвонить new MySingleton() извне самого класса. Чтобы "создать" MySingleton, вы должны позвонить MySingleton.GetMySingleton(thing). Этот вызов возвращает единственный экземпляр или создает, а затем возвращает его.

SimpleServiceLocator не может знать, как создать этот объект или откуда определить его зависимости.

Эта возможность может быть добавлена, если API предоставляет что-то вроде

public void Register<T>(Expression<Func<T>> staticFactoryMethod)…

… в этом случае вы можете вызвать Register(() => MySingleton.GetMySingleton());, но это будет работать только без параметров. Должно быть больше перегрузок:

public void Register<T, TParam1>(Expression<Func<TParam1, T>> staticFactoryMethod)…
public void Register<T, TParam1, TParam2>(Expression<Func<TParam1, TParam2, T>> staticFactoryMethod)…

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...