Вопрос на основе двух статей:
О синглтонах и статических конструкторах
Реализация синглтонов в .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. Ну и все танцы с бубном по делегированию структуре - вещь просто избыточная: она серьезно усложняет сопровождение без каких-либо выгод с точки зрения времени исполнения.
Комментариев нет:
Отправить комментарий