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

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();
        }
    }
}

Вот последовательность, которую я предположил

  • Начало статического конструктора
  • Конец статического конструктора
  • Начало основного
  • Начало MyMethod
  • Конец основного

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

Ответ 1

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

Вот последовательность, которую я предположил

  • Начало конструктора классов (также известный как cctor)
  • Конец работы
  • начало Главного
  • начало MyMethod

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

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

  • Начало программы для программы, если таковая есть. Нет.
  • Конец программы для программы, если таковой имеется. Нет.
  • Начало главного
  • Начало работы с программой для MyClass
  • Конец слова для MyClass
  • Начало MyClass.MyMethod

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

CLR разрешено изменять порядок, в котором запускаются инициализаторы статического поля в некоторых случаях. Более подробную информацию см. на странице Jon:

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

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

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

Коктор не вызывает MyMethod. Возможно ли, когда статический метод, например MyMethod, будет вызван до того, как завершит работу cctr MyClass?

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

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

Нет.

Правда ли это, даже если задействованы несколько потоков?

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

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

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

Потеряющая нить блокируется до тех пор, пока не будет выполнен cctor? Действительно?

На самом деле.

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

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

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

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

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

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

Ответ 2

В соответствии с MSDN статический конструктор:

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

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

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

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

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

Привет!

Привет!

Ответ 9

Здесь фактический порядок, в котором вещи опускаются:

  • Начало Main
  • Начало статического конструктора MyClass
  • Конец статического конструктора MyClass
  • Начало MyMethod
  • Конец Main

Ответ 10

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