Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharp Language Specification.doc
Скачиваний:
13
Добавлен:
26.09.2019
Размер:
4.75 Mб
Скачать

10.11.4Конструкторы по умолчанию

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

protected C(): base() {}

или

public C(): base() {}

где C – это имя класса.

Пример.

class Message { object sender; string text; }

В этом примере предоставлен конструктор по умолчанию, так как класс не содержит объявлений конструкторов экземпляров. Так, этот пример в точности эквивалентен следующему:

class Message { object sender; string text;

public Message(): base() {} }

10.11.5Закрытые конструкторы

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

public class Trig { private Trig() {} // Prevent instantiation

public const double PI = 3.14159265358979323846;

public static double Sin(double x) {...} public static double Cos(double x) {...} public static double Tan(double x) {...} }

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

10.11.6Необязательные параметры конструктора экземпляров

Вид this(...) инициализатора конструктора обычно используется в сочетании с перегрузкой для реализации необязательных параметров конструктора экземпляров. Пример.

class Text { public Text(): this(0, 0, null) {}

public Text(int x, int y): this(x, y, null) {}

public Text(int x, int y, string s) { // Actual constructor implementation } }

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

Text t1 = new Text(); // Same as Text(0, 0, null) Text t2 = new Text(5, 10); // Same as Text(5, 10, null) Text t3 = new Text(5, 20, "Hello");

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

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

объявление_статического_конструктора: атрибутынеобязательно модификаторы_статического_конструктора идентификатор ( ) тело_статического_конструктора

модификаторы_статического_конструктора: externнеобязательно static static externнеобязательно

тело_статического_конструктора: блок ;

Объявление_статического_конструктора может включать набор атрибутов (§17) и модификатор extern (§10.6.7).

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

Если в объявление статического конструктора включен модификатор extern, статический конструктор называется внешним статическим конструктором. Так как объявление внешнего статического конструктора не предоставляет фактическую реализацию, его тело_статического_конструктора состоит из точки с запятой. Для всех других объявлений статического конструктора тело_статического_конструктора состоит из блока, в котором указаны операторы, которые необходимо выполнить, чтобы инициализировать класс. Это в точности соответствует телу_метода статического метода с типом возвращаемого значения void (§10.6.10).

Статические конструкторы не наследуются и их нельзя вызвать непосредственно.

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

  • создан экземпляр типа класса;

  • возникла ссылка на любой статический член типа класса.

Если класс содержит метод Main (§3.1), в котором начинается исполнение, статический конструктор для этого класса выполняется до вызова метода Main.

Для инициализации нового закрытого типа класса сначала создается новый набор статических полей (§10.5.1) для этого особого типа класса. Каждое из статических полей инициализируется своим значением по умолчанию (§5.2). Затем выполняются инициализаторы этих статических полей (§10.4.5.1). Наконец выполняется статический конструктор.

Пример.

using System;

class Test { static void Main() { A.F(); B.F(); } }

class A { static A() { Console.WriteLine("Init A"); } public static void F() { Console.WriteLine("A.F"); } }

class B { static B() { Console.WriteLine("Init B"); } public static void F() { Console.WriteLine("B.F"); } }

Выходом этого примера должно быть:

Init A A.F Init B B.F

так как выполнение статического конструктора класса A запускается по обращению к A.F, а выполнение статического конструктора класса B запускается обращением к B.F.

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

Пример.

using System;

class A { public static int X;

static A() { X = B.Y + 1; } }

class B { public static int Y = A.X + 1;

static B() {}

static void Main() { Console.WriteLine("X = {0}, Y = {1}", A.X, B.Y); } }

В этом примере производятся следующие выходные данные

X = 1, Y = 2

Для выполнения метода Main система сначала выполняет инициализатор для B.Y, до статического конструктора класса B. Инициализатор Y вызывает запуск статического конструктора класса A, так как имеется ссылка на значение A.X. Статический конструктор A в свою очередь продолжает вычислять значение X и при этом вычислении выбирает значение по умолчанию для Y, которое равно нулю. A.X таким образом инициализируется значением 1. Процесс выполнения для класса A инициализаторов статических полей и статического конструктора затем завершается, возвращаясь к вычислению начального значения Y, результат которого становится равным 2.

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

class Gen<T> where T: struct { static Gen() { if (!typeof(T).IsEnum) { throw new ArgumentException("T must be an enum"); } } }

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]