2013-03-06 6 views
8

Прежде всего, я получил ответ в What is the use of static constructors?, но я хочу получить ответ в этом контексте.Зачем нам нужны статические конструкторы?

Вот мой C# статический класс:

public static class BasicClass 
{ 
    static int i = 0; 
    static BasicClass() 
    { 
     i = 10; 
    } 

    public static void Temp() 
    { 
     //some code 
    } 


    public static void Temp1() 
    { 
     //some code 
    } 
} 

Внутри этого у меня есть статическая переменная i которая инициализируется до 10, когда он первый называется. Таким образом, в основном это может быть цель статического конструктора, но одно и то же может быть достигнуто без объявления статического конструктора путем инициализации static int i = 10 , который служит той же цели, которая инициализируется только один раз.

Тогда зачем нам нужен статический конструктор? Или я совершенно не прав в понимании концепции или использования статических конструкторов?

+2

Что делать, если ваша программа использует файл конфигурации? Вы захотите сохранить свою конфигурацию в статических переменных, но сначала вам нужно будет прочитать их из файла, и если файл не существует (или вы не можете его открыть по каким-либо другим причинам), вы будете хотите установить эти конфигурации в значения по умолчанию. Для этого используется ** статический конструктор **. – Nolonar

ответ

22

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

Например, следующий C# код:

public static class BasicClass 
{ 
    static int i = 10; 
} 

будет производить IL эквивалент:

public static class BasicClass 
{ 
    static int i; 

    static BasicClass() 
    { 
     i = 10; 
    } 
} 

Другими словами, прямая инициализация только синтаксически обеспечивается C# компилятор. Под капотом статический конструктор все еще реализуется.

+0

В этом случае было бы недостаточно, если бы C# поддерживала статическую инициализацию члена (которая была бы фактически скомпилирована в статический конструктор), но не фактические статические конструкторы? – svick

+1

@ svick, что, возможно, будет контрпродуктивным. Иногда вам приходится выполнять операции, менее тривиальные, чем инициализация членов (например, простые петли и ветви) глобально для класса. Зачем удалять поддержку функции, доступной в CLR, и требует только, чтобы статический конструктор никогда не выбрасывал? –

0

Вы можете инициализировать поля только с константами времени компиляции (ваш случай). Но в статическом конструкторе вы можете выполнить некоторый код (например, прочитать файл конфигурации).

1

В этом сценарии не требуется статический конструктор.

static BasicClass() 
{ 
    i = 10; 
} 

и

static int i = 10; 

функционально идентичны.

6

Ну, в ваш пример действительно не нужен, но и представить, когда значение i должно считываться из базы данных, текстового файла или любого другого ресурса? Вам может понадобиться что-то вроде:

static BasicClass() 
{ 
    using (SomeConnection con = Provider.OpenConnection()) 
    { 
     try 
     { 
      // Some code here 
     } 
     catch 
     { 
      // Handling expeptions, setting default value 
      i = 10; 
     } 
    } 
} 

Теперь это не возможно объявить и инициализировать статическое поле, вы лучше подается с помощью статического конструктора

0

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

1

Ответ также в связанном вопросе:

[...] полезно, в частности, для чтения необходимых данных конфигурации в поля только для чтения и т.д.

Он запускается автоматически по времени выполнения в первый раз, когда это необходимо (точные правила там сложны (см. «Beforefieldinit») и тонко изменяются между CLR2 и CLR4). > Если вы не злоупотребляете отражением, гарантированно будет работать не более одного раза (даже если два потока> приходят одновременно).

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

1

Статический конструктор имеет смысл, если вам нужно выполнить некоторые действия внутри конструктора, и вы хотите получить уникальный экземпляр в приложении. Например:

public static class BasicClass 
{ 
    static MyConfiguration _myConfig; 

    static BasicClass() 
    { 
     // read configuration from file 
     _myConfig = ReadConfigFromConfigFile("somefile.conf"); 
    } 

    private static MyConfiguration ReadConfigFromConfigFile(string file) 
    { 
     using (StreamReader reader = new StreamReader(file); 
     { 
     ... 
     } 
    } 
} 

В описанном вами сценарии явно не требуется статический конструктор.

Кроме того, вы можете применить singleton pattern для достижения этой цели.

+3

-1, статические конструкторы не могут иметь параметры. –

+5

В статическом конструкторе опасно делать подобные вещи. Если инициализация выбрасывает неперехваченное исключение, тогда нет простого способа поймать его, а затем тип * никогда не будет загружаться в этот appdomain. –

0

Один из факторов, о которых еще не упоминалось, заключается в том, что существует семантическая разница между наличием статического конструктора (написанного с использованием синтаксиса конструктора), вызывающего foo(), в сравнении с инициализатором статического поля. В частности, если тип имеет статический конструктор, написанный с использованием синтаксиса конструктора, этот конструктор, как гарантируется, будет вызываться первым временным кодом, который будет «использовать» этот тип; он не будет вызываться до этого и не будет вызываться, если тип не используется. В отличие от этого, хотя .NET гарантирует, что инициализаторы статического поля типа будут выполняться до того, как будут доступны какие-либо из его статических полей, и не будут запускаться более одного раза, .NET может запускать такие статические инициализаторы, когда он считает, что тип может. Рассмотрим, например:

if (someCondition()) 
    for (i=0; i<100000000; i++) 
    someClass.someStaticField++; 

Если при Just-In-Time компилятор встречает приведенный выше код, someClass никогда не была использована, и это конструктор объявлен с использованием синтаксиса статический конструктор, полученный машинный код будет что-то вроде :

if (someCondition()) 
    for (i=0; i<100000000; i++) 
    { 
    if (someClass.hasBeenInitialized) 
     someClass.runConstructor(); 
    someClass.someStaticField++; 
    } 

, выполняющего если проверить в пределах цикла. Напротив, если бы были инициализации полей, но не было объявления типа конструктора, JIT, скорее всего, выполнил статическую конструкцию someClass перед запуском кода, тем самым устраняя необходимость включения в нее проверки if.

Смежные вопросы