Квалификаторы псевдонима пространства имен

Квалификатор псевдонима пространства имен :: дает возможность гарантировать, что на поиск имени типа не будет влиять введение новых типов и членов. Квалификатор псевдонима пространства имен всегда стоит между двумя идентификаторами, которые называют левым и правым. В отличие от регулярного квалификатора ., поиск левого идентификатора квалификатора :: выполняется только как поиск псевдонима extern или using.

Уточненный член псевдонима определяется следующим образом:

qualified-alias-member:
identifier :: identifier type-argument-listopt

Уточненный член псевдонима можно использовать как имя пространства имен или типа (§3.8) или как левый операнд доступа к члену (§7.6.4).

Уточненный член псевдонима может принимать одну из двух форм:

· N::I<A1, ..., AK>, где N и I представляют идентификаторы, а <A1, ..., AK> — список аргументов типа. (K всегда по меньшей мере единица);

· N::I, где N и I представляют идентификаторы. (В этом случае K считается равным нулю.)

При использовании этой нотации значение уточненного члена псевдонима определяется следующим образом:

· если N является идентификатором global, то поиск I ведется в глобальном пространстве имен:

o если в глобальном пространстве имен содержится пространство имен с именем I, а K равно нулю, то уточненный член псевдонима ссылается на это пространство имен;

o иначе, если в глобальном пространстве имен содержится неуниверсальный тип с именем I, а K равно нулю, то уточненный член псевдонима ссылается на этот тип;

o иначе, если в глобальном пространстве имен содержится тип с именем I, у которого имеется K параметров типа, то уточненный член псевдонима ссылается на этот тип, сформированный с данными аргументами типа;

o иначе уточненный член псевдонима не определен и выдается ошибка времени компиляции.

· иначе, начиная с объявления пространства имен (§9.2), непосредственно содержащего уточненный член псевдонима (если имеется), далее для каждого вмещающего объявления пространства имен (если имеются), и заканчивая единицей компиляции, содержащей уточненный член псевдонима, оцениваются следующие шаги, пока не будет обнаружена сущность:

o если в объявлении пространства имен или в единице компиляции содержится директива using alias, связывающая N с типом, то уточненный член псевдонима не определен и выдается ошибка времени компиляции;

o иначе, если в объявлении пространства имен или в единице компиляции содержится директива extern alias или директива using alias, связывающая N с пространством имен, то:

· если в пространстве имен, связанном с N, содержится пространство имен с именем I, а K равно нулю, то уточненный член псевдонима ссылается на это пространство имен;

· иначе, если в пространстве имен, связанном с N, содержится неуниверсальный тип с именем I, а K равно нулю, то уточненный член псевдонима ссылается на этот тип;

· иначе, если в пространстве имен, связанном с N, содержится тип с именем I, у которого имеется K параметров типа, то уточненный член псевдонима ссылается на этот тип, сформированный с данными аргументами типа;

· иначе уточненный член псевдонима не определен и выдается ошибка времени компиляции.

· иначе уточненный член псевдонима не определен и выдается ошибка времени компиляции.

Обратите внимание, что использование квалификатора псевдонима пространства имен с псевдонимом, ссылающимся на тип, вызывает ошибку времени компиляции. Кроме того, если N является идентификатором global, то поиск выполняется в глобальном пространстве имен, даже если существует псевдоним using, связывающий global с типом или пространством имен.

Уникальность псевдонимов

В каждой единице компиляции и теле пространства имен имеется отдельная область объявлений для псевдонимов extern и using. Так, хотя имя псевдонима extern или псевдонима using должно быть уникальным внутри набора псевдонимов extern и псевдонимов using, объявленных в непосредственно содержащей единице компиляции или теле пространства имен, псевдоним может иметь то же имя, что и тип или пространство имен, если он используется только с квалификатором ::.

В этом примере

namespace N
{
public class A {}

public class B {}
}

namespace N
{
using A = System.IO;

class X
{
A.Stream s1; // Error, A is ambiguous

A::Stream s2; // Ok
}
}

у имени A два возможных значения в теле второго пространства имен, так как и класс A, и псевдоним A находятся в области. Поэтому использование A в уточненном имени A.Stream неоднозначно и приводит к ошибке времени компиляции. Однако использование A с квалификатором :: не является ошибкой, так как поиск A ведется только как псевдонима пространства имен.




Классы

Класс — это структура данных, которая может содержать члены данных (константы и поля), члены функций (методы, свойства, события, индексаторы, операторы, конструкторы экземпляров, деструкторы и статические конструкторы) и вложенные типы. Типы классов поддерживают наследование — механизм, в котором производный класс может расширять и сужать базовый класс.

Объявления классов

Объявлением класса является объявление типа (§9.6), которое объявляет новый класс.

class-declaration:
attributesopt class-modifiersopt partialopt class identifier type-parameter-listopt
class-baseopt type-parameter-constraints-clausesopt class-body ;opt

Объявление класса состоит из необязательного набора атрибутов (§17), затем следует необязательный набор модификаторов класса (§10.1.1), необязательный модификатор partial, ключевое слово class и идентификатор, именующий класс, затем следует необязательный список параметров типа (§10.1.3), необязательная спецификация базы класса (§10.1.4), необязательный набор предложений ограничений параметров типа (§10.1.5), тело класса (§10.1.6) и необязательная точка с запятой.

Объявление класса не предоставляет предложения ограничений параметров типа, если не предоставляется список параметров типа.

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

Модификаторы классов

Объявление класса может включать последовательность модификаторов класса.

class-modifiers:
class-modifier
class-modifiers class-modifier

class-modifier:
new
public
protected
internal
private
abstract
sealed
static

Появление в объявлении класса одного и того же модификатора несколько раз является ошибкой времени компилирования.

Модификатор new допускается во вложенных классах. Он определяет скрытие классом унаследованного члена с тем же именем согласно описанию в разделе §10.3.4. Появление модификатора new в объявлении класса, не являющимся объявлением вложенного класса, является ошибкой времени компилирования.

Модификаторы public, protected, internal и private управляют доступом к классу. В зависимости от контекста, в котором возникает объявление класса, некоторые из данных модификаторов могут быть запрещены (§3.5.1).

Описание модификаторов abstract, sealed и static представлено в последующих разделах.

Абстрактные классы

Модификатор abstract используется для указания незавершенности класса и необходимости его использования только в качестве базового класса. Ниже представлены отличия абстрактного класса от неабстрактного.

· Абстрактный класс не может быть создан непосредственно, использование оператора new в абстрактном классе является ошибкой времени компилирования. Хотя есть возможность иметь переменные и значения, имеющие типы времени компиляции, являющиеся абстрактными типами, такие переменные и значения будут обязательно иметь значение null или будут содержать ссылки на экземпляры неабстрактных классов, производных от абстрактных типов.

· Абстрактный класс может (но не должен) содержать абстрактные члены.

· Абстрактный класс не может быть запечатанным.

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

abstract class A
{
public abstract void F();
}

abstract class B: A
{
public void G() {}
}

class C: B
{
public override void F() {
// actual implementation of F
}
}

В этом примере абстрактный класс A представляет абстрактный метод F. Класс B представляет дополнительный метод G, но так как он не предоставляет реализацию F, класс B должен быть также объявлен абстрактным. Класс C переопределяет F и обеспечивает фактическую реализацию. Так как в классе C нет абстрактных членов, класс C может быть (но не должен) быть абстрактным.

Запечатанные классы

Модификатор sealed используется для предотвращения создания из него производных классов. Если запечатанный класс указывается в качестве базового класса другого класса, возникает ошибка времени компилирования.

Запечатанный класс не может быть также абстрактным классом.

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

Статические классы

Модификатор static используется для пометки класса, объявленного в качестве статического класса. Для статического класса не может быть создан экземпляр, он не может быть использован в качестве типа и может содержать только статические члены. Только статический класс может содержать объявления методов расширения (§10.6.9).

На объявление статического класса накладываются следующие ограничения.

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

· Статический класс не может содержать спецификацию базы класса (§10.1.4) и не может явно указывать базовый класс или список реализованных интерфейсов. Статический класс неявно наследуется из типа object.

· Статический класс может содержать только статические члены (§10.3.7). Обратите внимание, что константны и вложенные типы классифицируются как статические члены.

· Статический класс не может содержать члены с объявленной доступностью protected или protected internal.

Нарушение данных ограничений приводит к ошибке времени компилирования.

Статический класс не имеет конструкторов экземпляров. Невозможно объявить конструктор экземпляров в статическом классе; конструктор экземпляров по умолчанию (§10.11.4) не предоставляется для статического класса.

Члены статического класса автоматически не являются статическими, а объявления членов должны явно включать модификатор static (исключая константы и вложенные типы). Если класс является вложенным внутри статического внешнего класса, вложенный класс не является статическим классом, если он явно не включает модификатор static.

Наши рекомендации