Поиск

Константы и неизменяемые поля

Можно с уверенностью сказать, что возникнут ситуации, когда изменение некоторых полей при выполнении приложения будет нежелательно. Например, это могут быть файлы данных, от которых зависит ваше приложение, значение pi для математического класса или любое другое используемое в приложении значение, о котором вы знаете, что оно никогда не изменится. В этих ситуациях С# позволяет определять члены двух тесно связанных типов: константы и неизменяемые поля.

Константы

Из названия легко догадаться, что константы (constants), представленные ключевым словом const, — это поля, остающиеся постоянными в течение всего времени жизни приложения. Определяя что-либо как const, достаточно помнить два правила. Во-первых, константа — это член, значение которого устанавливается в период компиляции программистом или компилятором (в последнем случае это значение по умолчанию). Во-вторых, значение члена-константы должно быть записано в виде литерала.

Чтобы определить поле как константу, укажите перед определяемым членом ключевое слово const:

using System;
class MagicNumbers {
public const double pi = 3.1415; public const int answerToAllLifesQuestions = 42; >
Glass ConstApp {
public static void MainQ {
Console.WriteLine("pi = {0}, все остальное = Ш",
MagicNumbers.pi, MagicNumbers.answerToAllLifesQuestions); } }

Обратите внимание на один важный момент, связанный с этим кодом. Клиенту нет нужды создавать экземпляр класса MagicNumbers, поскольку по умолчанию члены const являются статическими. Чтобы получить более четкое представление о предмете, взгляните на MSIL-код, сгенерированный для этих двух членов:

answerToAHLifesQuestions : public static literal int32
=int32(Ox0000002A) pi :public static literal float64
=float64(3.1415000000000002)
Неизменяемые поля

Поле, определенное как const, ясно указывает, что программист намерен поместить в него постоянное значение. Это плюс. Но оно работает, только если известно значение подобного поля в период компиляции. А что • же делать программисту, когда возникает потребность в поле, чье значение не известно до периода выполнения, но после инициализации не должно меняться? Эта проблема (которая обычно остается нерешенной в большинстве других языков) разрешена разработчиками языка С# с помощью неизменяемого поля (read-only field).

Определяя поле с помощью ключевого поля readonly, вы можете установить значение поля лишь в одном месте — в конструкторе. После этого поле не могут изменить ни сам класс, ни его клиенты. Допустим, для графического приложения нужно отслеживать разрешение экрана. Решить эту проблему с помощью const нельзя, так как до периода выполнения приложение не может определить разрешение экрана у пользователя. Поэтому для этой цели лучше всего использовать такой код:

using System;
class GraphicsPackage {
public readonly int ScreenWidth; public readonly int ScreenHeight;
public GraphicsPackageO {
this.ScreenWidth = 1024;
this.ScreenHeight = 768; } }
/^
class ReadOnlyApp /
{
public static void Main() {
GraphicsPackage graphics = new GraphicsPackageO;
Console.WrlteLine("Ширина = {0}, Высота = {1}", graphics.ScreenWidth,
graphics.ScreenHeight); > }

На первый взгляд кажется, что это то, что нужно. Но здесь одна маленькая проблема: определенные нами неизменяемые поля являются полями экземпляра, а значит, чтобы задействовать эти поля, пользователю придется создавать экземпляры класса. Может, это и не проблема, и этот код может даже пригодиться, когда значение неизменяемого поля определяется способом создания экземпляра класса. Но если вам нужна константа, по определению статическая, но инициализируемая в период выполнения? Тогда нужно определить поле с обоими модификаторами — static и readonly, а затем создать особый — статический — тип конструктора. Статические конструкторы (static constructor) используются для инициализации статических, неизменяемых и других полей. Здесь я изменил предыдущий пример так, чтобы сделать поля, определяющие разрешение экрана, статическими и неизменяемыми, а также добавил статический конструктор. Обратите внимание на ключевое слово static, добавленное к определению конструктора:

using Systero;
class GraphicsPackage {
public static readonly int ScreenWidth;
public static readonly int ScreenHeight;
static GraphicsPackageO {
// Здесь будет код для расчета разрешения экрана. ScreenWidth = 1024; ScreenHeight = 768; }
}
class ReadOnlyApp
{
public static void MainQ <
Console.WriteLine("Ширина = {0}, Высота = {1}", GraphicsPackage.ScreenWidth, GraphicsPackage.ScreenHeight); } }