Почему этот код DI объявляет переменную области действия метода, а затем назначает ее статическому объекту уровня класса?

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

Проблема заключается в методе BootStrapper(), который используется для инициализации статического контейнера SimpleInjector.

В этом методе объявляется var container и назначается новый Container(). В конце метода область действия метода container назначается статической переменной container уровня приложения.

Почему это делается именно так? Должна быть веская причина для назначения контейнера сначала локальной переменной var, а затем, наконец, назначению var статической переменной Container на уровне класса. Мне это кажется очевидным, избыточным назначением, но если это так, то я сомневаюсь, что кто-то будет делать это таким образом. Что мне не хватает?

Код ниже взят из кода из документации SimpleInjector. Я понимаю все, что делает код, я просто не понимаю смысла этого дополнительного назначения var.

using System.Windows;
using SimpleInjector;

public partial class App : Application
{
    private static Container container; //<-- The static, class-level variable. 
                                        //    Why not assign to it from the get-go?!

   //...snip...

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        Bootstrap();
    }

    private static void Bootstrap()
    {
        // Create the container as usual.
        var container = new Container();  //What's the point of this var?

        // Register your types, for instance:
        container.RegisterSingle<IUserRepository, SqlUserRepository>();
        container.Register<IUserContext, WpfUserContext>();

        // Optionally verify the container.
        container.Verify();

        // Store the container for use by the application.
        App.container = container;  //Couldn't we have done this from line 1 of this method?
    }
}

Источник: SimpleInjector — Руководство по интеграции Windows Presentation Foundation


person RLH    schedule 16.07.2013    source источник


Ответы (2)


Если контейнер сразу назначается статическому свойству, то статическое свойство будет ссылаться на контейнер, который еще не полностью инициализирован, что может иметь нежелательные последствия.

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

person lightbricko    schedule 16.07.2013
comment
См. мой вопрос в сообщении Кевина. - person RLH; 17.07.2013
comment
Одной из причин является многопоточность, но есть и другие способы, с помощью которых другие части кода могут получить доступ к частично инициализированному объекту. Зарегистрированные типы могут получить к нему доступ (например, WpfUserContext), и если возникнет исключение, метод Bootstrap может не завершить свое выполнение, и, следовательно, частично инициализированный объект никогда не станет полностью инициализированным. - person lightbricko; 17.07.2013
comment
Отличное (и несколько очевидное) замечание! Да, мне нужно будет прочитать об этом немного дальше. Это мой первый проект по внедрению зависимостей, и я буду использовать сервисы, которые должны будут ссылаться на сервисы. Я собираюсь обновить свои теги, потому что начинаю понимать, как это связано с SimpleInjector и DI. - person RLH; 17.07.2013

Я не знаю SimpleInjector, но возможной причиной может быть то, что RegisterSingle, Register или Verify могут генерировать исключение. Если один из них это сделает, вы можете остаться с App.Container в недопустимом состоянии, тогда как при таком способе App.Container останется либо в желаемом новом состоянии, либо останется нетронутым. Если Container является управляемым типом, вы получаете надежную защиту от исключений (http://en.wikipedia.org/wiki/Exception_safety).

person digitig    schedule 16.07.2013
comment
У меня была такая мысль, но, поскольку у метода не было оболочки try/catch, с тех пор это, похоже, не имело большого значения для меня. В текущих обстоятельствах исключение просто приведет к сбою приложения. - person RLH; 17.07.2013
comment
@RLH: это зависит от типа приложения и от того, когда в образе жизни приложения вызывается этот код, если он закрывает домен приложения приложения. Если это не приведет к сбою приложения, каждый последующий запрос или операция будут выдавать странное сообщение об исключении, скрывающее реальную проблему. Я сам был укушен этим в прошлом (хотя это не было приложение WPF). И хотя приложение WPF может умереть при сбое Application.OnStartUp, разработчики склонны копировать и вставлять эти примеры кода, поэтому я думаю, что не помешает написать несколько примеров кода, которые немного более надежны :-) - person Steven; 17.07.2013
comment
Основная причина исключений заключается в том, что вам не нужно обрабатывать их локально. Автор Bootstrap может не иметь ни малейшего представления о том, что будет подходящим ответом на исключение, потому что он понятия не имеет, что представляет собой конечное приложение. Позволяя исключению распространяться по дереву вызовов, автор передает ответственность за ответ на сбой клиенту, который находится в лучшем положении, чтобы сделать вызов (или передать его, в свою очередь, своему клиенту и т. д.). То, что код не заключен в блок try, не является признаком того, что код написан без учета безопасности исключений. - person digitig; 17.07.2013