Выбрать главу

Определение статических конструкторов

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

В целях иллюстрации модифицируйте код конструктора класса SavingsAccount, как показано ниже (также обратите внимание, что поле currInterestRate больше не устанавливается при объявлении):

class SavingsAccount

{

  public double currBalance;

  public static double currInterestRate;

  // Обратите внимание, что наш конструктор устанавливает

  // значение статического поля currInterestRate.

  public SavingsAccount(double balance)

  {

    currInterestRate = 0.04; // Это статические данные!

    currBalance = balance;

  }

  ...

}

Теперь добавьте к операторам верхнего уровня следующий код:

// Создать объект счета.

SavingsAccount s1 = new SavingsAccount(50);

// Вывести текущую процентную ставку.

Console.WriteLine("Interest Rate is: {0}", SavingsAccount.GetInterestRate());

// Попытаться изменить процентную ставку через свойство.

SavingsAccount.SetInterestRate(0.08);

// Создать второй объект счета.

SavingsAccount s2 = new SavingsAccount(100);

// Должно быть выведено 0.08, не так ли?

Console.WriteLine("Interest Rate is: {0}", SavingsAccount.GetInterestRate());

Console.ReadLine();

При выполнении этого кода вы увидите, что переменная currInterestRate сбрасывается каждый раз, когда создается новый объект SavingsAccount, и она всегда установлена в 0.04. Очевидно, что установка значений статических данных в нормальном конструкторе уровня экземпляра сводит на нет все их предназначение. Когда бы ни создавался новый объект, данные уровня класса сбрасываются! Один из подходов к установке статического поля предполагает применение синтаксиса инициализации членов, как делалось изначально:

class SavingsAccount

{

  public double currBalance;

  // Статические данные.

  public static double currInterestRate = 0.04;

  ...

}

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

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

class SavingsAccount

{

  public double currBalance;

  public static double currInterestRate;

  public SavingsAccount(double balance)

  {

    currBalance = balance;

  }

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

   static SavingsAccount()

   {

     Console.WriteLine("In static ctor!");

     currInterestRate = 0.04;

   }

...

}

Выражаясь просто, статический конструктор представляет собой специальный конструктор, который является идеальным местом для инициализации значений статических данных, если их значения не известны на этапе компиляции (например, когда значения нужно прочитать из внешнего файла или базы данных, сгенерировать случайные числа либо получить значения еще каким-нибудь способом). Если вы снова запустите предыдущий код, то увидите ожидаемый вывод. Обратите внимание, что сообщение "In static ctor!" выводится только один раз, т.к. среда CoreCLR вызывает все статические конструкторы перед первым использованием (и никогда не вызывает их заново для данного экземпляра приложения):

***** Fun with Static Data *****

In static ctor!

Interest Rate is: 0.04

Interest Rate is: 0.08

Ниже отмечено несколько интересных моментов, касающихся статических конструкторов.

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