Страницы

Поиск по вопросам

суббота, 15 июня 2019 г.

Статический конструктор структуры и инициализация синглтона

Вопрос на основе двух статей:
О синглтонах и статических конструкторах Реализация синглтонов в .NET: Field-like vs. Lazy
Собственно, вспомнил, что у структур несколько иначе обстоят дела с вызовом статического конструктора (он вызывается перед обращением к статическому полю, но не вызывается при создании инстанса структуры). Соответственно, возникло желание поместить свойство Instance внутрь структуры. Сначала я хотел что-то намудрить с красотой обращения к нему, но потом передумал и решил спросить по самому концепту - даёт ли это что-то помимо ленивой инициализации (кстати, а действительно ли она тут гарантирована) и есть ли какие-то побочные эффекты?.
http://ideone.com/BrgjAI
using System;
struct FieldLikeSingletonWrapper { public class FieldLikeSingleton { internal FieldLikeSingleton() { Console.WriteLine("FieldLikeSingleton.ctor"); }
public void Foo() { Console.WriteLine("Foo"); } }
public static FieldLikeSingleton Instance { get; } = new FieldLikeSingleton(); }
class Program { static void Main(string[] args) { Console.WriteLine("Inside Main()");
if (args.Length == 42) { FieldLikeSingletonWrapper.Instance.Foo(); } } }
Кстати, сначала мне казалось очевидным, что сделать сам синглтон структурой - идея ужасная, поскольку структура будет копироваться. Но потом я подумал, что можно объявить прокинуть методы через структуру (да, это минус), но использовать скрытый вложенный класс:
http://ideone.com/Ok1XP0
using System;
struct FieldLikeSingleton { private class FieldLikeSingletonImpl { internal FieldLikeSingletonImpl() { Console.WriteLine("FieldLikeSingleton.ctor"); }
public void Foo() { Console.WriteLine("Foo"); } }
private static FieldLikeSingletonImpl instance = new FieldLikeSingletonImpl(); public static FieldLikeSingleton Instance { get; }
public void Foo() { instance.Foo(); } }
class Program { static void Main(string[] args) { Console.WriteLine("Inside Main()");
if (args.Length == 42) { FieldLikeSingleton.Instance.Foo(); } } }
Какие плюсы и минусы есть у этих подходов по сравнению с обычным field-like?


Ответ

вспомнил, что у структур несколько иначе обстоят дела с вызовом статического конструктора (он вызывается перед обращением к статическому полю, но не вызывается при создании инстанса структуры).
Это не совсем так. Точнее, это так, если считать, что default(T) - это единственный способ создания экземпляра структуры. Да, в случае var x = new FooStruct() статический конструктор не вызывается, поскольку в этом случае происходит просто выделение и обнуление блока памяти. Если бы в этом случае была проверка инициализации типа, то это привело бы к существенным накладным расходам во время исполнения (а ведь структуры предназначены именно для таких low-level сценариев, где каждый такт имеет значение).
Аналогично, при копировании структуры статический конструктор не будет вызван:
var @default = new FooStruct(); // нет вызова статического конструктора var copy = @default; // нет вызова статического конструктора
Однако при вызове пользовательского конструктора структуры, статический конструктор будет вызван (это же будет справедливым и для пользовательского конструктора по-умолчанию; его нельзя создать в C#, но если создадите, то статический конструктор будет вызываться и для var x = new FooStruct()):
var instance = new FooStruct(42);
Вообще, тут нужно понять, какую именно проблему вы хотите решить.
Если вопрос с ленивостью инициализации синглтона, то наличие поля Instance во вложенном классе сделает поведение полностью ленивым:
class SomeSingleton { private class SingletonHolder { public static readonly SomeSingleton Instance = new SomeSingleton(); }
public static SomeSingleton Instance => SingletonHolder.Instance; }
В этом случае обращение к статическим членам класса SomeSingleton не приведет к инициализации синглтона. Единственный способ инициализации синглтона - обращение к свойству Instance
Подчеркну: это решение полностью ленивое, но оно страдает остальными проблемами field-like синглтонов, связанных с исключениями.
P.S. Ну и все танцы с бубном по делегированию структуре - вещь просто избыточная: она серьезно усложняет сопровождение без каких-либо выгод с точки зрения времени исполнения.

Комментариев нет:

Отправить комментарий