2016-01-26 5 views
5

Я пытаюсь понять необходимость создания статических конструкторов. Никакой информации, которую я нашел, не ответил на следующий вопрос, который у меня есть. Зачем ты этоПопытка понять статические конструкторы

class SimpleClass 
{ 
    // Static variable that must be initialized at run time. 
    static readonly long baseline; 

    // Static constructor is called at most one time, before any 
    // instance constructor is invoked or member is accessed. 
    static SimpleClass() 
    { 
     baseline = DateTime.Now.Ticks; 
    } 
} 

в противоположность этому

class SimpleClass 
{ 
    // Static variable that must be initialized at run time. 
    static readonly long baseline = DateTime.Now.Ticks; 

    // Static constructor is called at most one time, before any 
    // instance constructor is invoked or member is accessed. 
    //static SimpleClass() 
    //{ 

    //} 
} 

?


Это не обманывает другой вопрос, речь идет о статических конструкторах, которые не принимают параметры.

+0

Это не статический вопрос, вопрос действительно и для нестатической инициализации. –

+0

Возможный дубликат [Инициализировать поля класса в конструкторе или в объявлении?] (Http://stackoverflow.com/questions/24551/initialize-class-fields-in-constructor-or-at-declaration) –

+0

@CyrilGandon Это не обман - это о статических конструкторах, которые не принимают параметры. Попробуйте удалить тег dupe. –

ответ

5

Необходимость как-то очевидна: вы хотите сделать больше, чем инициализацию поля для ваших статических членов.

Логически, если у вас есть этот класс:

class SimpleClass 
{ 
    // Static variable that must be initialized at run time. 
    static readonly long baseline = DateTime.Now.Ticks; 


} 

Вы можете переписать его, чтобы иметь тот же эффект:

class SimpleClass 
{ 
    // Static variable that must be initialized at run time. 
    static readonly long baseline; 

    static SimpleClass() { 
     baseline = DateTime.Now.Ticks; 
    } 
} 

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

От J effrey Рихтер CLR с помощью C# книги:

Когда C# компилятор видит класс со статическими полями, которые используют встроенный инициализации (класс BeforeFieldInit), компилятор генерирует запись таблицы определения типа в класса, с флагом BeforeFieldInit метаданных , Когда компилятор C# видит класс с явным конструктором типа (класс Precise), компилятор испускает тип таблицы класса без флага метаданных BeforeFieldInit. Обоснование заключается в следующем: инициализация статических полей должна выполняться до доступа к полям, тогда как явный конструктор типа может содержать произвольный код, который может иметь наблюдаемые побочные эффекты ; этот код может потребоваться для выполнения в определенное время.

Obviouselly есть нечто большее, чем это происходит за кулисами, я хотел бы предложить вам прочитать всю главу из CLR через C#: «Тип Конструкторы»

+5

Ну, они не совсем то же самое - класс со статическим конструктором может иметь разные времена инициализации по сравнению с классом, который имеет только инициализаторы статического поля. См. Http://csharpindepth.com/Articles/General/Beforefieldinit.aspx –

+0

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

+0

@JonSkeet Может быть, вы можете ответить –

3

Это пример возможного различия:

class SimpleClass 
{ 
    static readonly long A = DateTime.Now.Ticks; 
    static readonly long B = DateTime.Now.Ticks; 

    static SimpleClass() 
    { 
    } 
} 

A и B не гарантируется иметь то же значение, хотя, если вы напишете его в конструкторе, вы можете это гарантировать:

class SimpleClass 
{ 
    static readonly long A; 
    static readonly long B; 

    static SimpleClass() 
    { 
     var ticks = DateTime.Now.Ticks; 
     A = ticks; 
     B = ticks; 
    } 
} 

Кроме того, заказывает вопросы для создания статических элементов.

Согласно ECMA-334 относительно статической инициализации поля:

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

Таким образом, мы можем написать что-то вроде этого:

class SimpleClass 
{ 
    public static readonly long A = IdentityHelper.GetNext(); 
    public static readonly long B = IdentityHelper.GetNext(); 

    static SimpleClass() 
    { 
    } 
} 

public static class IdentityHelper 
{ 
    public static int previousIdentity = 0; 
    public static int GetNext() 
    { 
     return ++previousIdentity; 
    } 
} 

Здесь A гарантированно назначается до B. В этом примере A будет 1, а B будет 2. Мы можем гарантировать, что A < B (при условии, что идентификатор не переполняется, и нет проблем с потоками). Теперь, если мы изменить порядок полей:

public static readonly long B = IdentityHelper.GetNext(); 
public static readonly long A = IdentityHelper.GetNext(); 

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

Более вероятный сценарий, мы хотим сделать это:

class SimpleClass 
{ 
    public static readonly long A = IdentityHelper.GetExpensiveResult().A; 
    public static readonly long B = IdentityHelper.GetExpensiveResult().B; 

    static SimpleClass() 
    { 
    } 
} 

Здесь мы не можем разделить GetExpensiveResult() между полями.

+0

Крошечное пятно кода, которое не связано с вопросом, 'return ++ currentIdentity' лучше, иначе у вас всегда будет' IdentityHelper.currentIdentity == IdentityHelper.GetNext() ' –

+0

@DannyChen Вы правы - спасибо:) – Rob

+0

@ Danny Chen, не могли бы вы рассказать о своем последнем комментарии? Я не совсем уверен, что понимаю, как это работает –

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