Как работает статический конструктор? - PullRequest
80 голосов
/ 22 февраля 2012
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 ]

217 голосов
/ 22 февраля 2012

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

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

  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.

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

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

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

номер

Это все еще верно, даже если задействовано несколько потоков?

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

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

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

Потеряная нить блокирует до тех пор, пока не будет завершен цикл? Действительно

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

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

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

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

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

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

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

23 голосов
/ 22 февраля 2012

Согласно MSDN , статический конструктор:

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

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

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

11 голосов
/ 22 февраля 2012

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

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

9 голосов
/ 22 февраля 2012

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

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

2 голосов
/ 22 февраля 2012

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

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

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

Привет!

Привет!

2 голосов
/ 22 февраля 2012

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

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

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

2 голосов
/ 22 февраля 2012

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

2 голосов
/ 22 февраля 2012

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

1 голос
/ 03 марта 2012

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

  1. Начало Main
  2. Начало статического MyClass конструктора
  3. Конецстатический MyClass конструктор
  4. начало MyMethod
  5. конец Main
0 голосов
/ 29 февраля 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...