Как работает статический конструктор?


namespace MyNameSpace
{
    static class MyClass
    {
        static MyClass()
        {
            //Authentication process.. User needs to enter password
        }

        public static void MyMethod()
        {
            //Depends on successful completion of constructor
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass.MyMethod();
        }
    }
}

вот последовательность которую я предполагал

  1. запуск статического конструктора
  2. конец статического конструктора
  3. главным
  4. начало MyMethod
  5. Конец главной

теперь в любом случае если 4 начнется до 2 я облажался. Возможно ли это?

10 80

10 ответов:

вы задали только один вопрос здесь, но есть дюжина или около того вопросов, которые вы должны спросили, Так что я отвечу на них всех.

вот последовательность которую я предполагал

  1. запуск конструктора класса (также известный как cctor)
  2. конец cctor
  3. главным
  4. начало MyMethod

это правильно?

нет. Этот правильная последовательность:

  1. запуск cctor для программы, если она есть. Нет.
  2. конец cctor для программы, если он есть. Нет.
  3. главным
  4. запуск cctor для MyClass
  5. конец cctor для MyClass
  6. начало MyClass.MyMethod

что делать, если есть инициализатор статического поля?

CLR разрешено изменять порядок в котором инициализаторы статического поля выполняются в некоторых случаях. См. страницу Джона по этому вопросу для получения дополнительной информации:

различия между статическими конструкторами и инициализаторами типов

это не возможно для статического метода типа MyMethod вызывается до завершения cctor этого класса?

да. если cctor сам вызывает MyMethod, то, очевидно, MyMethod будет вызван перед cctor завершает.

cctor не вызывает MyMethod. Это вообще возможно для статического метода типа MyMethod вызывается до завершения cctor MyClass?

да. если cctor использует другой тип, cctor которого вызывает MyMethod, то MyMethod будет вызван до завершения cctor MyClass.

никакие cctors не вызывают MyMethod, прямо или косвенно! Теперь это когда-нибудь возможно для статического метода, как MyMethod будет вызывается до завершения cctor MyClass?

нет.

это все еще верно, даже если есть несколько потоков, участвующих?

да. Cctor завершится на одном потоке, прежде чем статический метод может быть вызван на любом потоке.

можно ли вызвать cctor более одного раза? Предположим, что два потока оба вызывают запуск cctor.

cctor гарантированно будет вызван не более одного раза, независимо от того сколько потоков задействовано. Если два потока называют MyMethod "одновременно", то они участвуют в гонке. Один из них проигрывает гонку и блокирует, пока MyClass cctor не завершит победный поток.

потерять нить блоки пока cctor не будет сделано? действительно?

действительно.

Ну и что, если cctor на победы поток вызывает код, который блокирует блокировку ранее принятых проигрыш нить?

тогда у вас есть классическое условие инверсии порядка блокировки. Ваши программные тупики. Навсегда.

Это кажется опасным. Как я могу избежать тупика?

если это больно, когда вы это делаете, то прекрати. никогда не делайте то, что может блокировать в cctor.

это хорошая идея, чтобы полагаться на cctor семантика инициализации для реализации комплекса требования безопасности? И это хорошая идея, чтобы иметь cctor, который делает взаимодействия с пользователями?

ни одна из хороших идей. Мой совет заключается в том, что вы должны найти другой способ обеспечить выполнение предварительных условий, влияющих на безопасность ваших методов.

по словам MSDN, статический конструктор:

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

Так что статический конструктор будет вызван перед статическим методом MyClass.MyMethod() вызывается (если не и вызывается во время статической конструкции или инициализации статического поля, конечно).

теперь, если вы делаете что-то асинхронное в этом static constructor, тогда это ваша работа, чтобы синхронизировать это.

#3 На самом деле #1: статическая инициализация не запускается до первого использования класса, к которому он принадлежит.

это возможно, если MyMethod вызывается из статического конструктора или блока статической инициализации. Если вы не вызываете MyMethod прямо или косвенно из вашего статического конструктора, вы должны быть в порядке.

с документация (выделено мной):

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

вы можете гарантировать, что 4 всегда будет после 2 (Если вы не создадите экземпляр своего класса из своего статического метода), однако то же самое не верно для 1 и 3.

статический конструктор будет вызван до выполнения mymethod. Однако если вы привинчены, если 4 вызывается до 2, то я предлагаю вам пересмотреть свой дизайн. В любом случае не следует делать сложные вещи в статическом конструкторе.

среда CLR гарантирует, что статический конструктор запускается до обращения к любым статическим членам. Тем не менее, ваш дизайн немного вонючий. Было бы проще сделать что-то вроде этого:

static void Main(string[] args) 
{ 
     bool userIsAuthenticated = MyClass.AuthenticateUser();
     if (userIsAuthenticated)
         MyClass.MyMethod(); 
 } 

в вашем проекте, если аутентификация не выполняется, единственный способ предотвратить запуск MyMethod-это создать исключение.

гарантируется, что конструктор статического класса был вызван до выполнения любого из его методов. Пример:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press enter");
        Console.ReadLine();
        Boop.SayHi();
        Boop.SayHi();
        Console.ReadLine();
    }

}

static class Boop
{
    static Boop()
    {
        Console.WriteLine("Hi incoming ...");
    }

    public static void SayHi()
    {
        Console.WriteLine("Hi there!");
    }
}

выход:

нажмите enter

// после нажатия enter

Привет входящих ...

Привет!

Привет!

вот фактический порядок, в котором все идет вниз:

  1. начало Main
  2. начало статический!--1--> конструктор
  3. конец статический!--1--> конструктор
  4. начало MyMethod
  5. конец Main

или вы можете пройти через отладчик.