статический класс "инициализировать" шаблон в C #? - PullRequest
7 голосов
/ 17 марта 2012

В чем выгода или причина использования этого шаблона? ..

public sealed class myStaticClass
{
    private static bool _initialized;
    private static object _lockObject;

    private static string _someStaticField;
    private static int _anotherStaticField;
    private static string _nthStaticField;

    static myStaticClass()
    {
        _initialized = false;  
        _lockObject = new object();
    }

    public myStaticClass()
    {
    }

    public static void Initialize()
    {
        if(!_initialized)
        {
            lock(_lockObject)
            {
                if(!_initialized)
                {
                    //do initializing
                    _someStaticField = someApplicationSetting;
                    _anotherStaticField = anotherApplicationSetting;
                    _nthStaticField = nthApplicationSetting;

                    _initialized = true;
                }
            }
        }
    }

    public static string NthStaticField 
    { 
        get {

            Initialize();
            return _nthOtherField;
        }
    }
}

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

РЕДАКТИРОВАТЬ: Я обновил шаблон, чтобы лучше отражать класс в .net Framework, где я его обнаружил,Я изменил модификатор static в классе на sealed, а также добавил пустой конструктор public.

пс.Если вы хотели бы знать, класс, в котором я видел этот шаблон, это класс FormsAuthentication.

Ответы [ 3 ]

2 голосов
/ 17 марта 2012

Единственная причина для этого может быть, если инициализация дорогая (с точки зрения ЦП / ОЗУ) ИЛИ что-то необходимое доступно только позже во время выполнения IMO ... эта реализация задерживает инициализацию до самого последнего возможного момента (прямо перед первым доступом).Это то, что Lazy<T> предлагает ...

1 голос
/ 17 марта 2012

Возможно, ApplicationSettings не будут доступны позже во время выполнения.

0 голосов
/ 19 марта 2012

Хорошо. Теперь я прочитал и рассмотрел данные ссылки и пришел к выводу, что этот конкретный пример не сломан.

Я объясню, почему ...

Во-первых, это не тот же шаблон, что и в статье csharpindepth csharpindepth.com / Articles / General / Singleton.aspx .Шаблон в этой статье предназначен для одного человека.Шаблон, который я представил, не является одноэлементным, у него есть открытый конструктор, однако все его поля являются статическими.Таким образом, большая разница в том, что шаблон csharpindepth возвращает ссылку на одноэлементный объект, даже если он на самом деле не был полностью создан.Ключевым моментом является то, что экземпляр может быть присвоен ссылке до того, как конструктор завершит работу.

public sealed class Singleton
{
 private static Singleton instance = null;
 private static readonly object padlock = new object();

Singleton()
 {
 }

public static Singleton Instance
 {
     get
     {
         if (instance == null)
         {
             lock (padlock)
             {
                 if (instance == null)
                 {
                     instance = new Singleton();
                 }
             }
         }
         return instance;
     }
 }
} 

это шаблон csharpindepth, и он работает следующим образом ..

Если есть 3 потока A, B и C. Поток A вызывает метод Instance, экземпляр равен null, онполучает замок.Теперь, прежде чем поток A создаст экземпляр Sigleton, появится поток B, экземпляр по-прежнему нулевой.Но у А есть замок, поэтому Б ждет.Пока B ожидает, поток A выполняет код instance = new Instance().В этот момент экземпляр устанавливается на экземпляр Singleton, однако возможно, что он еще не был построен. Вот где безопасность потока нарушается. Вдоль потока C он видит, что экземпляр не равен NULL, поэтому метод Instance возвращает ссылку на экземпляр. Но поток A еще не завершил создание экземпляра, поэтому поток C и любые другие потоки, которые были введены одновременно с потоком C, получают ссылку на пустой экземпляр Singleton.Наконец, A заканчивает, B получает блокировку, но работа теперь выполняется, поэтому она завершается.

Шаблон, который я представил, значительно отличается. Поле, которое используется для двойной проверки,не экземпляр, созданный в методе Initialize.Это простой private static bool, который используется в качестве переключателя.Поскольку это не ссылка на объект Singleton, который еще предстоит построить, и поскольку к нему никогда не обращаются за пределами этого класса, проблема не возникает.

Проблема может возникнуть, если установлен переключатель private static bool _initializedв true до того, как поля класса были инициализированы, но это не так.Это последнее, что должно произойти до того, как код снимет блокировку.Таким образом, нет никакого шанса, что поток C прочитает _initialized и ошибочно принимает класс за инициализацию.И так в любом случае это не Бокен.

...