Статический конструктор, называемый конструктором экземпляра?

Дорогой, вопрос, подобный этому, уже был уже задан, но среди ответов не было объяснения проблемы, которую я вижу.

Проблема: Руководство по программированию на С#:

Статический конструктор используется для инициализации любых статических данных или для выполнения определенного действия, которое требуется выполнить только один раз. Он вызывается автоматически до создания первого экземпляра или ссылки на любые статические члены.

В частности, статический конструктор вызывается до создания любого экземпляра класса. (Это не гарантирует, что статический конструктор заканчивается перед созданием экземпляра, но это совсем другая история.)

Рассмотрим пример кода:

using System;

public class Test
{
    static public Test test = new Test();
    static Test()
    {
        Console.WriteLine("static Test()");
    }
    public Test()
    {
        Console.WriteLine("new Test()");
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Main() started");
        Console.WriteLine("Test.test = " + Test.test);
        Console.WriteLine("Main() finished");
    }
}

Он выводит:

Main() запущен
новый тест()
статический тест()
Test.test = Тест
Main() завершено

Итак, мы видим, что конструктор экземпляра заканчивается (и, таким образом, создается экземпляр) до запуска статического конструктора. Разве это не противоречит Руководству? Может быть, инициализация статических полей считается неявной частью статического конструктора?

Ответ 1

В строковых инициализаторах для полей static выполняется перед явным конструктором static.

Компилятор преобразует ваш класс в нечто вроде этого:

public class Test {
    .cctor {    //Class constructor
        Test.test = new Test();                //Inline field initializer
        Console.WriteLine("static Test()");    //Explicit static ctor
    }
    .ctor { ... }    //Instance constructor
}

Обратите внимание, что это не зависит от порядка объявления.

Чтобы процитировать spec:

Инициализаторы статической переменной поля класса соответствуют последовательности назначений, выполняемых в текстовый порядок, в котором они появляются объявление класса. Если статический конструктор (раздел 10.11) существует в класс, выполнение статического инициализаторы полей перед выполнением этого статического конструктор.