Реализация синглтона с пустым статическим конструктором

Я просматривал следующую реализацию Singleton, упомянутую здесь. Я понимаю, что статические конструкторы выполняются до первого вызова статического метода или до создания экземпляра объекта, но не понял его использования здесь (даже из комментариев). Может ли кто-нибудь помочь мне понять это?

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

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Singleton()
    {
    }

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

person Nemo    schedule 16.03.2012    source источник
comment
Это объясняется в пунктах под ним, в частности: The laziness of type initializers is only guaranteed by .NET when the type isn't marked with a special flag called 'beforefieldinit'. Unfortunately, the C# compiler (as provided in the .NET 1.1 runtime, at least) marks all types which don't have a static constructor (i.e. a block which looks like a constructor but is marked static) as 'beforefieldinit'. Итак, он хочет, чтобы new Singleton() создавался как можно позже (лениво), и единственный способ заставить компилятор C# сделать это - предоставить пустой статический конструктор.   -  person porges    schedule 16.03.2012
comment
Простите мое невежество. Что такое лень инициализаторов типов. Это инициализация по первому запросу?   -  person Nemo    schedule 16.03.2012
comment
Точно. Это гарантировано только в этой ситуации, в противном случае среда выполнения может запускать инициализаторы типов, когда захочет, например, как только тип будет загружен. Для более подробного объяснения см. ссылку в ответе Джея.   -  person porges    schedule 16.03.2012


Ответы (1)


Статический конструктор существует не для того, чтобы его вызывали до или после чего-либо еще, а только для того, чтобы компилятор не устанавливал флаг beforefieldinit.

Подробнее об этом здесь: Что делает флаг beforefieldinit?

Обоснование состоит в том, чтобы добиться некоторой лени при инициализации одноэлементного объекта. Если задано beforefieldinit (поскольку статический конструктор не определен), то выполнение метода, который условно ссылается на Singleton.Instance, скорее всего, инициализирует одноэлементный объект, даже если условие не выполняется и этот вызов никогда не выполняется.

public void Foo()
{
    if (false)
    {
        var bar = Singleton.Instance.SomeMethod();
    }
}

С другой стороны, если beforefieldinit не задано (поскольку определен статический конструктор - даже пустой), то выполнение того же метода приведет к инициализации экземпляра синглтона только в том случае, если условие выполнено и этот вызов на самом деле сделано.

Далее в этой статье указывается, что эта конкретная реализация не является полностью ленивой, поскольку вызов любого другого статического члена, который вы определяете в классе singleton, также приведет к инициализации Instance.

person Jay    schedule 16.03.2012