Какая польза от статических конструкторов?

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

11 ответов

Решение

Нет, вы не можете его перегрузить; Статический конструктор полезен для инициализации любых статических полей, связанных с типом (или любых других операций для каждого типа) - особенно полезен для чтения требуемых данных конфигурации в полях только для чтения и т. д.

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

Из статических конструкторов (Руководство по программированию в C#):

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

Статические конструкторы имеют следующие свойства:

  • Статический конструктор не принимает модификаторы доступа и не имеет параметров.

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

  • Статический конструктор не может быть вызван напрямую.

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

  • Типичное использование статических конструкторов - это когда класс использует файл журнала, а конструктор используется для записи записей в этот файл.

  • Статические конструкторы также полезны при создании классов-оболочек для неуправляемого кода, когда конструктор может вызвать LoadLibrary метод.

Статические конструкторы также очень полезны, когда у вас есть статические поля, которые зависят друг от друга, так что важен порядок инициализации. Если вы выполняете свой код через форматтер /beautifier, который меняет порядок полей, то вы можете оказаться с нулевыми значениями там, где вы их не ожидали.

Пример: предположим, у нас был этот класс:

class ScopeMonitor
{
    static string urlFragment = "foo/bar";
    static string firstPart= "http://www.example.com/";
    static string fullUrl= firstPart + urlFragment;
}

Когда вы получаете доступ fullUr, это будет " http://www.example.com/foo/bar".

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

class ScopeMonitor
{
    static string firstPart= "http://www.example.com/";
    static string fullUrl= firstPart + urlFragment;
    static string urlFragment = "foo/bar";
}

Ваш fullUrl значение теперь просто " http://www.example.com/", так как urlFragment не был инициализирован в то время fullUrl был установлен. Нехорошо. Итак, вы добавляете статический конструктор, чтобы позаботиться об инициализации:

class ScopeMonitor
{
    static string firstPart= "http://www.example.com/";
    static string fullUrl;
    static string urlFragment = "foo/bar";

    static ScopeMonitor()
    {
        fullUrl= firstPart + urlFragment;

    }
}

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

1. Он может получить доступ только к статическим членам класса.

Причина: Нестатический член относится к экземпляру объекта. Если статическому конструктору разрешено работать с нестатическими элементами, он будет отражать изменения во всех экземплярах объекта, что нецелесообразно.

2. В статическом конструкторе не должно быть параметров.

Причина: поскольку он будет вызываться CLR, никто не может передать ему параметр. 3. Допускается только один статический конструктор.

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

4. Не должно быть никакого модификатора доступа к нему.

Причина: снова причина в том, что тот же самый вызов статического конструктора выполняется CLR, а не объектом, нет необходимости иметь модификатор доступа к нему

Вы можете использовать статический конструктор для инициализации статических полей. Он запускается в неопределенное время, прежде чем эти поля используются. Документация Microsoft и многие разработчики предупреждают, что статические конструкторы для типа накладывают существенные накладные расходы.
Лучше избегать статических конструкторов для максимальной производительности.
обновление: вы не можете использовать более одного статического конструктора в одном классе, однако вы можете использовать другие конструкторы экземпляров с (максимум) одним статическим конструктором.

Почему и когда мы создали бы статический конструктор...?

Одной из конкретных причин использования статического конструктора является создание класса 'super enum'. Вот (простой, надуманный) пример:

public class Animals
{
    private readonly string _description;
    private readonly string _speciesBinomialName;

    public string Description { get { return _description; } }
    public string SpeciesBinomialName { get { return _speciesBinomialName; } }

    private Animals(string description, string speciesBinomialName)
    {
        _description = description;
        _speciesBinomialName = speciesBinomialName;
    }

    private static readonly Animals _dog;
    private static readonly Animals _cat;
    private static readonly Animals _boaConstrictor;

    public static Animals Dog { get { return _dog; } }
    public static Animals Cat { get { return _cat; } }
    public static Animals BoaConstrictor { get { return _boaConstrictor; } }

    static Animals()
    {
        _dog = new Animals("Man's best friend", "Canis familiaris");
        _cat = new Animals("Small, typically furry, killer", "Felis catus");
        _boaConstrictor = new Animals("Large, heavy-bodied snake", "Boa constrictor");
    }
}

Вы бы использовали его очень сходным образом (в синтаксическом виде) с любым другим перечислением:

Animals.Dog

Преимущество этого перед обычным enum является то, что вы можете легко инкапсулировать связанную информацию. Одним из недостатков является то, что вы не можете использовать эти значения в switch утверждение (потому что это требует постоянных значений).

Из документации Microsoft https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

Статические конструкторы (Руководство по программированию на C#)

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

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

Примечания

Статические конструкторы обладают следующими свойствами:

  • Статический конструктор не принимает модификаторы доступа и не имеет параметров.
  • Класс или структура может иметь только один статический конструктор.
  • Статические конструкторы нельзя наследовать или перегружать.
  • Статический конструктор нельзя вызвать напрямую, и он предназначен только для вызова средой CLR. Он вызывается автоматически.
  • Пользователь не может контролировать, когда в программе выполняется статический конструктор.
  • Статический конструктор вызывается автоматически. Он инициализирует класс перед созданием первого экземпляра или ссылкой на любые статические члены, объявленные в этом классе (не в его базовых классах). Статический конструктор запускается перед конструктором экземпляра. Статический конструктор типа вызывается при вызове статического метода, назначенного событию или делегату, а не при его назначении. Если в классе статического конструктора присутствуют инициализаторы переменных статического поля, они выполняются в текстовом порядке, в котором они появляются в объявлении класса. Инициализаторы запускаются непосредственно перед выполнением статического конструктора.
  • Если вы не предоставляете статический конструктор для инициализации статических полей, все статические поля инициализируются до значения по умолчанию, как указано в разделе Значения по умолчанию для типов C#.
  • Если статический конструктор создает исключение, среда выполнения не вызывает его во второй раз, и тип остается неинициализированным на протяжении всего времени существования домена приложения. Чаще всего исключение xref:System.TypeInitializationException возникает, когда статический конструктор не может создать экземпляр типа или если в статическом конструкторе возникает необработанное исключение. Для статических конструкторов, которые не определены явно в исходном коде, устранение неполадок может потребовать проверки кода промежуточного языка (IL).
  • Наличие статического конструктора предотвращает добавление атрибута типа xref:System.Reflection.TypeAttributes.BeforeFieldInit. Это ограничивает оптимизацию во время выполнения.
  • Поле, объявленное как static readonlyможет быть назначен только как часть его объявления или в статическом конструкторе. Если явный статический конструктор не требуется, инициализируйте статические поля при объявлении, а не через статический конструктор для лучшей оптимизации времени выполнения.
  • Среда выполнения вызывает статический конструктор не более одного раза в одном домене приложения. Этот вызов выполняется в заблокированной области на основе определенного типа класса. Никаких дополнительных механизмов блокировки в теле статического конструктора не требуется. Чтобы избежать риска взаимоблокировок, не блокируйте текущий поток в статических конструкторах и инициализаторах. Например, не ждите задач, потоков, дескрипторов ожидания или событий, не получайте блокировки и не выполняйте блокирующие параллельные операции, такие как параллельные циклы, Parallel.Invokeи параллельные запросы LINQ.

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

Применение

  • Типичное использование статических конструкторов — это когда класс использует файл журнала, а конструктор используется для записи записей в этот файл.
  • Статические конструкторы также полезны при создании классов-оболочек для неуправляемого кода, когда конструктор может вызывать LoadLibraryметод.
  • Статические конструкторы также являются удобным местом для принудительной проверки во время выполнения параметра типа, который нельзя проверить во время компиляции с помощью ограничений параметра типа.

Static constructorвызывается только первый экземпляр созданного класса. и используется для выполнения определенного действия, которое необходимо выполнить только один раз в жизненном цикле класса.

Статический конструктор

Конструктор, объявленный с использованием статического модификатора, является статическим конструктором. Статический конструктор используется для инициализации статических данных или для выполнения определенного действия, которое необходимо выполнить только один раз в жизненном цикле класса. Статический конструктор - это первый блок кода, который нужно выполнить в классе. Статический конструктор выполняет один и только один раз в жизненном цикле класса. Он вызывается автоматически. Статический конструктор не принимает никаких параметров. У него нет спецификаторов доступа. Это не вызывается напрямую.

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

Источник: http://www.c-sharpcorner.com/article/static-constructor-in-C-Sharp-and-their-usages/

using System;
namespace Constructor
{
class Test
{
//Declaration and initialization of static data member 
private static int id = 5;
public static int Id
{
get
{
return id;
}
}
public static void print()
{
Console.WriteLine("Test.id = " + id);
}
static void Main(string[] args)
{
//Print the value of id 
Test.print();
}
}
}

In the above example, static data member <id> is declared and initialized in same line. So if you compile and run this program your output would look similar to this :

Test.id = 5

Lets create one more class similar to class Test but this time the value of its static data member would depend on the value of static data member <id> of class Test.id.

//File Name : Test1.cs
using System;
namespace Constructor
{
class Test1
{
private static int id ;
//Static constructor, value of data member id is set conditionally here. 
//This type of initialization is not possible at the time of declaration.
static Test1()
{
if( Test.Id < 10 )
{
id = 20;
}
else
{
id = 100; 
}
Console.WriteLine("Static<Class> Constructor for Class Test1 Called..");
}
public static void print()
{
Console.WriteLine("Test1.id = " + id);
}
static void Main(string[] args)
{
//Print the value of id 
Test1.print();
}
}
}

As you can see in the above static constructor, static data member <id> is initialized conditionally. This type of initialization is not possible at the time of declaration. This is where static constructor comes in picture

Другие вопросы по тегам