Re: ваш PS
Автор статьи на Хабре самоуверенно порет чушь.
Начнём с главного: его код синглтона не потокобезопасен! Разбор:
if(instance != null) return instance;
// (*)
Monitor.Enter(s_lock);
Singleton temp = new Singleton();
Interlocked.Exchange(ref instance, temp);
Monitor.Exit(s_lock);
return instance;
Пусть поток 1 начинает выполнять приведённый код. instance в этот момент есть null, так что первая проверка проходит, и выполнение доходит до строки (*).
Пусть в этот момент произойдёт переключение контекста (это ведь возможно, правильно?), и начинает выполняться второй поток. Он точно так же проверяет instance, проходит начальную проверку, пробегает через (*), получает lock, создаёт экземпляр синглтона, записывает его в instance, отпускает lock и выходит. Второй поток получает ссылку на instance только что созданного синглтона.
Теперь управление получает первый поток. Он точно так же получает lock, создаёт второй экземпляр синглтона, записывает его в instance, затирая старое значение, отпускает lock и выходит. Первый поток получает ссылку на другой объект.
Катастрофа.
Теперь по мелочам. Разработчики .NET не просто так сделали lock(obj) синонимом Monitor.Enter(obj, ref lockTaken), а не просто Monitor.Enter(obj). Вариант с Monitor.Enter(obj) работает неправильно в случае, если возможны исключения. Поэтому замена lock на явный Monitor.Enter — ухудшение.
Ещё большее ухудшение — отказ от try/catch. Без базара, без try/catch быстрее, только код получается неправильный. (Впрочем, если правильный код нам не нужен, без lock'а было бы ещё быстрее.) Если по каким-то причинам конструктор Singleton'а выбросит исключение (а это может быть не только деление на 0, но и TypeLoadException, например), то s_lock останется залоченным навсегда — deadlock.
Затем, автор критикует правильные, рекомендованные экспертами (а Jon Skeet — мегаэксперт) имплементации под совершенно надуманными предлогами. По поводу подхода «через readonly поле» автор пишет:
Конструктор может быть только статичным. Это особенность компилятора — если конструткор не статичен, то тип будет помечен как beforefieldinit и readonly создадутся одновременно со static-ами.
Это фактически неверно, автор судя по всему просто не понял, что именно написал Jon. У синглтона есть нестатический конструктор, просто явный статический конструктор должен присутствовать. Между «статический конструктор должен присутствовать» и «конструктор может быть только статичным» огромная разница.
Правильная, остроумная, каноническая реализация синглтона с вложенным классом удостоилась лишь замечания «Недостатки у него те же самые, что у любого другого кода, который использует nested-классы». Мне неизвестны недостатки вызванные одним лишь наличием вложенных классов. Если мне кто-либо сообщит, готов изменить своё мнение.
Наконец, самое концептуально верное решение с Lazy<T> критикуется за то, что оно «не работает с потоками», а используют структуры языка, которые «обманывают интерпретатор». Здесь неверно вообще всё, кроме союзов и предлогов. Начнём с того, что C# — компилируемый язык, интерпретатора C# не существует. Затем, никакого обмана нет: Lazy<T> работает строго как обещает его документация. То, что его поведение отличается от поведения других классов — не обман и не трюк. При желании то же самое можно заимплементировать самому вручную.
Затем, правильным при реализации синглтона является не многопоточность или прочие технические мелочи, а простой инвариант: как бы синглтон не использовался, всегда гарантировано наличие не более одного экземпляра синглтона на AppDomain. Именно это гарантируется классом Lazy<T>. Используются ли при этом специальные механизмы для поддержки многопоточности или свойства языка, никому не интересно. Главное — чтобы семантика единственного экземпляра была выдержана. Именно это гарантирует класс Lazy<T>, абстрагируя нас от деталей реализации. И именно поэтому такая имплементация — самая правильная.
Вывод: не все статьи на Хабре одинаково полезны.
дзен:) – VladD May 22 '14 at 17:05Имплементация, которую вы приводите, неверна, т. к. между строчками
и
поле
– VladD May 22 '14 at 17:08instanceможет быть инициализировано из другого потока.В данном случае целесообразно реализовать класс формы в виде синглтона?
по-моему, это весьма сомнительное применение данному патерну. Во всяком случае судя по вышеуказанным данным
– DreamChild May 27 '14 at 14:25Если просто разместить datagridview то это будет несложно реализовать, но это будет крайне некрасиво при большИх таблицах.
– teanЫЧ May 27 '14 at 14:40DataGridавтоматически подстраивается под тип таблицы.В любом случае, с таблицей имеет право общаться лишь модель, view имеет право лишь отображать данные (из модели или VM, в зависимости от выбранного архитектурного паттерна) и передавать контроллеру/VM пользовательский ввод. В такой постановке view может быть отконфигурировано контроллером для конкретного типа таблицы (а может и самоотконфигурироваться).
Но это уже тема для отдельного обсуждения.
– VladD May 27 '14 at 14:56