Подтвердить что ты не робот

Использование контейнеров IoC; в частности, Виндзор

Я думаю, что ответ на этот вопрос настолько порок, что никто не беспокоился об этом, но его поздно, и я действительно не могу обдумать это.

Я читал в контейнерах IoC (Windsor в этом случае), и мне не хватает, как вы разговариваете с контейнером из разных частей вашего кода.

Я получаю DI, я делал плохой mans DI (пустые конструкторы, вызывающие перегруженные конструкторы инъекций с реализацией параметров по умолчанию) в течение некоторого времени, и я могу полностью увидеть преимущества контейнера. Тем не менее, я пропустил одну важную часть информации; как вы должны ссылаться на контейнер каждый раз, когда вам нужна услуга?

Создаю ли я единое глобальное ощущение, которое я прохожу? Наверняка нет!

Я знаю, что я должен назвать это:

WindsorContainer container = new WindsorContainer(new XmlInterpreter());

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

Неспособность понять это мешает мне понять, как работают жизненные циклы, и продолжать использовать некоторые преимущества IoC

Спасибо,

Эндрю

4b9b3361

Ответ 1

99% случаев - один экземпляр контейнера для каждого приложения. Обычно вы инициализируете его в Application_Start (для веб-приложения), как это.

После этого, это действительно до потребителя контейнера. Например, некоторые фреймворки, такие как Monorail и ASP.NET MVC позволяет вам перехватывать создание экземпляров (в этом случае контроллеры), поэтому вы просто регистрируете контроллеры и их зависимости в контейнере и что он, всякий раз, когда вы получаете запрос, контейнер заботится о каждом инъекции контроллер с его зависимостями. См. Например этот ASP.NET MVC-контроллер. В этих рамках вам вряд ли когда-либо понадобится вызывать или даже ссылаться на контейнер в ваших классах, что является рекомендуемым использованием.

Другие фреймворки не позволяют легко входить в процесс создания (например, Webforms), поэтому вам нужно прибегать к хакам, например этот, или вытащите необходимые зависимости (то есть, явным образом вызываю контейнер). Чтобы вытащить зависимости, используйте статический шлюз в контейнер, например этот или тот, который описывается maxnk. Обратите внимание, что, делая это, вы фактически используете контейнер в качестве локатора сервисов, который не отделяет вещи, а также от инверсии элемента управления. (см. разницу здесь и здесь)

Надеюсь, это уберет ваши сомнения.

Ответ 2

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

Другой популярный подход заключается в том, чтобы обернуть экземпляр контейнера статическим классом и использовать этот статический класс для доступа к вашему (singleton) контейнеру. Вы можете найти пример этого в библиотеке Ayende Rhino.Commons здесь. Однако этот подход имеет серьезные недостатки и его следует избегать.

Ответ 4

В качестве других ответов здесь говорится, что есть много вариантов, и мы снова должны сами выяснить, что лучше в нашем случае.

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

С Unity у вас действительно может быть параметр IUnityContainer в вашем конструкторе, и контейнер автоматически добавит себя в экземпляр при разрешении класса, Таким образом, для служб, которым необходимо разрешить другие службы, которые вы передаете в контейнере, вместо того, чтобы заставить класс ссылаться на внешний класс.

Не знаете, как другие фреймворки поддерживают этот сценарий (Windsor будет вводить IKernel).

Ответ 5

Я использую реализацию этого интерфейса:

public interface IResolver
{
    object Resolve(Type type);
    object Resolve(string name);

    T Resolve<T>() where T : class;
    T Resolve<T>(string name) where T : class;
}

который фактически завернут в глобальный статический класс, например:

public static class Resolver // : IResolver
{
    private static IResolver _current;

    public static object Resolve(Type type)
    {
        return Current.Resolve(type);
    }

    public static object Resolve(string name)
    {
        return Current.Resolve(name);
    }

    public static T Resolve<T>() where T : class
    {
        return Current.Resolve<T>();
    }

    public static T Resolve<T>(string name) where T : class
    {
        return Current.Resolve<T>(name);
    }

    private static IResolver Current
    {
        get
        {
            if (_current == null)
            {
                _current = new SpringResolver();
            }

            return _current;
        }
    }
}

Также я пытаюсь следовать простому правилу: используйте класс Resolver как можно меньше, вместо этого добавьте сервисы в объекты, которым нужны эти службы.