Статический конструктор может запускаться после нестатического конструктора. Это ошибка компилятора?

Выход из следующей программы:

Non-Static
Static
Non-Static

Это ошибка компилятора? Я ожидал:

Static
Non-Static
Non-Static

потому что я думал, что статический конструктор ВСЕГДА вызывался перед нестатическим конструктором.

Я проверил это в Visual Studio 2010, используя.net 3.5 и.net 4.0.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StaticConstructorBug
{
    class Program
    {
        static void Main(string[] args)
        {
            var mc = new MyClass();

            Console.ReadKey();
        }
    }

    public class MyClass
    {
        public MyClass()
        {
            Console.WriteLine("Non-static");
        }

        static MyClass()
        {
            Console.WriteLine("Static");
        }

        public static MyClass aVar = new MyClass();
    }
}

4 ответа

Решение

См. ECMA 334 §17.4.5.1:

17.4.5.1 Инициализация статического поля

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

В частности: "выполнение инициализаторов статического поля происходит непосредственно перед выполнением этого статического конструктора".

Ваш static MyClass aVar должен быть инициализирован перед выполнением вашего статического конструктора (или, по крайней мере, он должен выглядеть таким образом). Без этого статического члена статический конструктор должен вызываться перед любыми нестатическими конструкторами.

Если вы все еще хотите MyClass singleton, вы можете поместить его в контейнерный класс и ссылаться на него, например:

public static class MyClassSingleton
{
    public static MyClass aVar = new MyClass();
}

Это вызвано линией public static MyClass aVar = new MyClass();,

На самом деле aVar = new MyClass(); является предисловием к статическому конструктору. Итак, ваш статический конструктор:

static MyClass() {
    Console.WriteLine("Static");
}

изменено на:

static MyClass() {
    aVar = new MyClass(); // this will run instance contstructor and prints "Non-Static"
    Console.WriteLine("Static");
}

Это public static MyClass aVar = new MyClass(); является частью вашего статического конструктора. Если вы посмотрите на него с помощью отражателя, вы увидите следующее:

static MyClass()
{
    aVar = new Program.MyClass();
    Console.WriteLine("Static");
}

Так что ваш результат должен быть очевиден сейчас.

Из MSDN Link:

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

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

Другие вопросы по тегам