Поделиться через


14 Пространств имен

14.1 Общие

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

Директивы using (§14.5) предоставляются для упрощения использования пространств имен.

Единицы компиляции 14.2

Compilation_unit состоит из нуля или более extern_alias_directive, за которым следует нулевая или более using_directive, а затем нулевая или одна global_attributes, за которой следует ноль или более namespace_member_declaration. Compilation_unit определяет общую структуру входных данных.

compilation_unit
    : extern_alias_directive* using_directive* global_attributes?
      namespace_member_declaration*
    ;

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

Extern_alias_directive единицы компиляции влияют на using_directive, global_attributes и namespace_member_declaration этого модуля компиляции, но не влияют на другие единицы компиляции.

Using_directive единицы компиляции влияют на global_attributes и namespace_member_declarationэтого модуля компиляции, но не влияют на другие единицы компиляции.

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

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

Пример:

// File A.cs:
class A {}
// File B.cs:
class B {}

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

пример конца

Объявления пространства имен 14.3

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

namespace_declaration
    : 'namespace' qualified_identifier namespace_body ';'?
    ;

qualified_identifier
    : identifier ('.' identifier)*
    ;

namespace_body
    : '{' extern_alias_directive* using_directive*
      namespace_member_declaration* '}'
    ;

Namespace_declaration может возникать как объявление верхнего уровня в compilation_unit или как объявление члена в другом namespace_declaration. Когда namespace_declaration происходит как объявление верхнего уровня в compilation_unit, пространство имен становится членом глобального пространства имен. Когда namespace_declaration происходит в другом namespace_declaration, внутреннее пространство имен становится членом внешнего пространства имен. В любом случае имя пространства имен должно быть уникальным в пределах содержащего пространства имен.

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

В namespace_body необязательный using_directiveимпортирует имена других пространств имен, типов и членов, что позволяет ссылаться на них напрямую, а не через квалифицированные имена. Необязательный namespace_member_declarationвносит вклад членов в пространство объявления пространства имен. Обратите внимание, что все using_directiveдолжны отображаться перед объявлениями членов.

Qualified_identifier namespace_declaration может быть одним идентификатором или последовательностью идентификаторов, разделенных. "" маркерами. Последняя форма позволяет программе определять вложенное пространство имен без лексического вложения нескольких объявлений пространства имен.

Пример:

namespace N1.N2
{
    class A {}
    class B {}
}

семантически эквивалентен

namespace N1
{
    namespace N2
    {
        class A {}
        class B {}
    }
}

пример конца

Пространства имен открыты, и два объявления пространства имен с одинаковым полным именем (§7.8.2) вносят свой вклад в одно и то же пространство объявлений (§7.3).

Пример. В следующем коде

namespace N1.N2
{
    class A {}
}

namespace N1.N2
{
    class B {}
}

Два объявления пространства имен, приведенные выше, способствуют одному и тому же пространству объявлений, в этом случае объявляя два класса с полными именами N1.N2.A и N1.N2.B. Так как два объявления способствуют одному и тому же пространству объявлений, это было бы ошибкой, если каждая из них содержала объявление члена с одинаковым именем.

пример конца

Директивы псевдонима Extern 14.4

В extern_alias_directive представлен идентификатор, который служит псевдонимом для пространства имен. Спецификация псевдонима пространства имен является внешней к исходному коду программы и применяется также к вложенным пространствам имен псевдонима пространства имен.

extern_alias_directive
    : 'extern' 'alias' identifier ';'
    ;

Область extern_alias_directive распространяется на using_directive s, global_attributes и namespace_member_declaration его немедленно содержащих compilation_unit или namespace_body.

В блоке компиляции или тексте пространства имен, содержащего extern_alias_directive, идентификатор, представленный extern_alias_directive, можно использовать для ссылки на псевдонимное пространство имен. Это ошибка во время компиляции для идентификатора, который должен быть словомglobal.

Псевдоним, представленный extern_alias_directive, очень похож на псевдоним, представленный using_alias_directive. Дополнительные сведения о extern_alias_directiveи using_alias_directiveсм. в статье 14.5.2.

alias — это контекстное ключевое слово (§6.4.4) и имеет особое значение только при немедленном выполнении ключевого extern слова в extern_alias_directive.

Ошибка возникает, если программа объявляет экстерн-псевдоним, для которого отсутствует внешнее определение.

Пример: следующая программа объявляет и использует два экстерна псевдонима, X и Yкаждый из которых представляет корень отдельной иерархии пространства имен:

extern alias X;
extern alias Y;

class Test
{
    X::N.A a;
    X::N.B b1;
    Y::N.B b2;
    Y::N.C c;
}

Программа объявляет существование экстерн-псевдонимов X и Y, однако фактические определения псевдонимов являются внешними для программы. Теперь классы с одинаковыми именами N.B можно ссылаться как X.N.B и (или Y.N.B) с помощью квалификатора X::N.B пространства имен и Y::N.B. пример конца

Директивы using 14.5

14.5.1 Общие

Директивы using упрощают использование пространств имен и типов, определенных в других пространствах имен. Использование директив влияет на процесс разрешения имен namespace_or_type_name(§7.8) и simple_name(§12.8.4), но в отличие от объявлений, using_directiveне вносят новых членов в базовые пространства объявлений единиц компиляции или пространств имен, в которых они используются.

using_directive
    : using_alias_directive
    | using_namespace_directive
    | using_static_directive    
    ;

В using_alias_directive (§14.5.2) представлен псевдоним пространства имен или типа.

Using_namespace_directive (§14.5.3) импортирует элементы типа пространства имен.

Using_static_directive (§14.5.4) импортирует вложенные типы и статические элементы типа.

Область using_directive расширяется по namespace_member_declarations его немедленного содержимого, содержащего блок компиляции или тело пространства имен. Область using_directive, в частности, не включает его одноранговые using_directives. Таким образом, одноранговые using_directiveне влияют друг на друга, и порядок, в котором они написаны, незначителен. В отличие от этого, область extern_alias_directive включает using_directive, определенные в том же модуле компиляции или теле пространства имен.

14.5.2 Использование директив псевдонима

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

using_alias_directive
    : 'using' identifier '=' namespace_or_type_name ';'
    ;

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

Пример:

namespace N1.N2
{
    class A {}
}
namespace N3
{
    using A = N1.N2.A;

    class B: A {}
}

Выше в объявлениях членов в N3 пространстве имен используется псевдоним, N1.N2.Aпоэтому класс N3.B является производным от классаN1.N2.AA. Тот же эффект можно получить путем создания псевдонима R для N1.N2 и последующего R.Aссылки:

namespace N3
{
    using R = N1.N2;

    class B : R.A {}
}

пример конца

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

Пример: например:

namespace N1
{
    extern alias N2;

    class B : N2::A {}
}

Выше в объявлениях членов в N1 пространстве имен используется псевдоним для определенного пространства имен, N2 определение которого является внешним исходным кодом программы. Класс N1.B является производным от класса N2.A. Тот же эффект можно получить путем создания псевдонима A для N2.A и последующего Aссылки:

namespace N1
{
    extern alias N2;

    using A = N2::A;

    class B : A {}
}

пример конца

Extern_alias_directive или using_alias_directive делает псевдоним доступным в определенном блоке компиляции или теле пространства имен, но не вносит новых членов в базовое пространство объявлений. Другими словами, директива псевдонима не является транзитивной, но, скорее, влияет только на блок компиляции или тело пространства имен, в котором она происходит.

Пример. В следующем коде

namespace N3
{
    extern alias R1;

    using R2 = N1.N2;
}

namespace N3
{
    class B : R1::A, R2.I {} // Error, R1 and R2 unknown
}

области директив псевдонима, которые вводят R1 и R2 расширяют только объявления членов в теле пространства имен, в котором они содержатся, поэтому R1 и R2 неизвестны во втором объявлении пространства имен. Однако размещение директив псевдонима в блоке компиляции приводит к тому, что псевдоним становится доступным в обоих объявлениях пространства имен:

extern alias R1;

using R2 = N1.N2;

namespace N3
{
    class B : R1::A, R2.I {}
}

namespace N3
{
    class C : R1::A, R2.I {}
}

пример конца

Каждый extern_alias_directive или using_alias_directive в compilation_unit или namespace_body вносит имя в пространство объявления псевдонима (§7.3) немедленного включающего compilation_unit или namespace_body. Идентификатор директивы псевдонима должен быть уникальным в соответствующем пространстве объявления псевдонима. Идентификатор псевдонима не должен быть уникальным в пределах глобального пространства объявлений или пространства объявления соответствующего пространства имен.

Пример:

extern alias X;
extern alias Y;

using X = N1.N2; // Error: alias X already exists

class Y {} // Ok

Именованный псевдоним X используется, так как в той же единице компиляции уже есть псевдоним X . Именованный класс Y не конфликтует с псевдонимом extern, Y так как эти имена добавляются в отдельные пространства объявлений. Первый добавляется в глобальное пространство объявления, а последний добавляется в пространство объявлений псевдонима для этой единицы компиляции.

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

namespace N1.N2
{
    class B {}
}

namespace N3
{
    class A {}
    class B : A {}
}

namespace N3
{
    using A = N1.N2;
    using B = N1.N2.B;

    class W : B {} // Error: B is ambiguous
    class X : A.B {} // Error: A is ambiguous
    class Y : A::B {} // Ok: uses N1.N2.B
    class Z : N3.B {} // Ok: uses N3.B
}

Во втором тексте N3пространства имен для неквалифицированного использования B результатов ошибки, так как N3 содержит элемент с именем B и тело пространства имен, которое также объявляет псевдоним с именемB; аналогично.A N3.B Класс можно ссылаться как N3.B или global::N3.B. Псевдоним можно использовать в элементе с полным псевдонимом A (§14.8), например.A::B Псевдоним B по сути бесполезен. Его нельзя использовать в qualified_alias_member , так как только псевдонимы пространства имен можно использовать в qualified_alias_member и B псевдонимах типа.

пример конца

Как и обычные члены, имена, представленные alias_directives , скрыты аналогичным именованным элементами в вложенных областях.

Пример. В следующем коде

using R = N1.N2;

namespace N3
{
    class R {}
    class B: R.A {} // Error, R has no member A
}

Ссылка на R.A объявление B вызывает ошибку во время компиляции, так как R ссылается на N3.Rнее.N1.N2

пример конца

Порядок записи extern_alias_directiveне имеет значения. Аналогичным образом, порядок записи using_alias_directiveне имеет значения, но все using_alias_directives должны поступать после всех extern_alias_directiveв одном блоке компиляции или теле пространства имен. Разрешение namespace_or_type_name, на который ссылается using_alias_directive, не влияет на сам using_alias_directive или другие using_directiveв немедленном тексте модуля компиляции или пространства имен, но могут повлиять на extern_alias_directiveв немедленном блоке компиляции или теле пространства имен. Иными словами, namespace_or_type_name using_alias_directive разрешается так, как если бы немедленно содержащий модуль компиляции или текст пространства имен не имел using_directives, но имеет правильный набор extern_alias_directives.

Пример. В следующем коде

namespace N1.N2 {}

namespace N3
{
    extern alias X;

    using R1 = X::N; // OK
    using R2 = N1; // OK
    using R3 = N1.N2; // OK
    using R4 = R2.N2; // Error, R2 unknown
}

последняя using_alias_directive приводит к ошибке во время компиляции, так как она не влияет на предыдущую using_alias_directive. Первая using_alias_directive не приводит к ошибке, так как область действия экстерн-псевдонима X включает using_alias_directive.

пример конца

Using_alias_directive может создать псевдоним для любого пространства имен или типа, включая пространство имен, в котором он отображается, и любое пространство имен или тип, вложенные в это пространство имен.

Доступ к пространству имен или типу с помощью псевдонима дает точно тот же результат, что и доступ к пространству имен или типу через объявленное имя.

Пример: задано

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using R1 = N1;
    using R2 = N1.N2;

    class B
    {
        N1.N2.A a; // refers to N1.N2.A
        R1.N2.A b; // refers to N1.N2.A
        R2.A c; // refers to N1.N2.A
    }
}

имена N1.N2.A, R1.N2.Aи эквивалентны и R2.A все ссылаются на объявление класса, полное имя которого .N1.N2.A

пример конца

Хотя каждая часть частичного типа (§15.2.7) объявлена в одном пространстве имен, части обычно записываются в разных объявлениях пространства имен. Таким образом, для каждой части могут присутствовать разные extern_alias_directiveи using_directive. При интерпретации простых имен (§12.8.4) в одной части рассматриваются только extern_alias_directive и using_directiveтел пространства имен и единиц компиляции, включающих ее. Это может привести к тому, что один и тот же идентификатор имеет разные значения в разных частях.

Пример:

namespace N
{
    using List = System.Collections.ArrayList;

    partial class A
    {
        List x; // x has type System.Collections.ArrayList
    }
}

namespace N
{
    using List = Widgets.LinkedList;

    partial class A
    {
        List y; // y has type Widgets.LinkedList
    }
}

пример конца

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

Пример:

namespace N1
{
    class A<T>
    {
        class B {}
    }
}

namespace N2
{
    using W = N1.A;       // Error, cannot name unbound generic type
    using X = N1.A.B;     // Error, cannot name unbound generic type
    using Y = N1.A<int>;  // Ok, can name closed constructed type
    using Z<T> = N1.A<T>; // Error, using alias cannot have type parameters
}

пример конца

14.5.3 С помощью директив пространства имен

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

using_namespace_directive
    : 'using' namespace_name ';'
    ;

В объявлениях членов в тексте блока компиляции или пространства имен, содержащего using_namespace_directive, можно ссылаться непосредственно на типы, содержащиеся в заданном пространстве имен.

Пример:

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1.N2;

    class B : A {}
}

Выше в объявлениях членов в N3 пространстве имен члены N1.N2 члены являются доступными напрямую и таким образом класс N3.B является производным от класса N1.N2.A.

пример конца

Using_namespace_directive импортирует типы, содержащиеся в заданном пространстве имен, но в частности не импортируют вложенные пространства имен.

Пример. В следующем коде

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1;
    class B : N2.A {} // Error, N2 unknown
}

using_namespace_directive импортирует типы, содержащиеся в N1, но не пространства имен, вложенные в N1. Таким образом, ссылка на N2.A объявление приводит к ошибке во время компиляции B , так как именованные N2 элементы не находятся в области.

пример конца

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

Пример:

namespace N1.N2
{
    class A {}
    class B {}
}

namespace N3
{
    using N1.N2;
    class A {}
}

Здесь, в объявлениях членов в N3 пространстве имен, A ссылается N3.A на нее N1.N2.A.

пример конца

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

Пример. В следующем коде

namespace N1
{
    class A {}
}

namespace N2
{
    class A {}
}

namespace N3
{
    using N1;
    using N2;

    class B : A {} // Error, A is ambiguous
}

N1 и N2 содержит элементA, и, поскольку N3 импортирует оба, ссылка A в N3 нее является ошибкой во время компиляции. В этой ситуации конфликт можно решить либо с помощью квалификации ссылок Aна , либо путем введения using_alias_directive , который выбирает конкретный A. Например:

namespace N3
{
    using N1;
    using N2;
    using A = N1.A;

    class B : A {} // A means N1.A
}

пример конца

Кроме того, если несколько пространств имен или типов импортируются using_namespace_directive или using_static_directiveв одном модуле компиляции или тексте пространства имен содержат типы или члены с тем же именем, ссылки на это имя как simple_name считаются неоднозначными.

Пример:

namespace N1
{
    class A {}
}

class C
{
    public static int A;
}

namespace N2
{
    using N1;
    using static C;

    class B
    {
        void M()
        {
            A a = new A();   // Ok, A is unambiguous as a type-name
            A.Equals(2);     // Error, A is ambiguous as a simple-name
        }
    }
}

N1 содержит элемент Aтипа и C содержит статическое поле A, и так как N2 импортирует оба, ссылка A как simple_name является неоднозначной и ошибкой во время компиляции.

пример конца

Как и using_alias_directive, using_namespace_directive не вносит новых членов в базовое пространство объявления единицы компиляции или пространства имен, но, скорее, влияет только на модуль компиляции или тело пространства имен, в котором она отображается.

Namespace_name, на который ссылается using_namespace_directive, разрешается так же, как и namespace_or_type_name, на который ссылается using_alias_directive. Таким образом, using_namespace_directiveв одном модуле компиляции или теле пространства имен не влияют друг на друга и могут быть записаны в любом порядке.

14.5.4 Использование статических директив

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

using_static_directive
    : 'using' 'static' type_name ';'
    ;

В объявлениях членов в тексте модуля компиляции или пространства имен, содержащего using_static_directive, доступные вложенные типы и статические члены (кроме методов расширения), содержащиеся непосредственно в объявлении данного типа, можно ссылаться напрямую.

Пример:

namespace N1
{
   class A 
   {
        public class B {}
        public static B M() => new B();
   }
}

namespace N2
{
    using static N1.A;

    class C
    {
        void N()
        {
            B b = M();
        }
    }
}

В приведенном выше коде в объявлениях членов в N2 пространстве имен статические члены и вложенные типы N1.A доступны напрямую, поэтому метод N может ссылаться как на B элементы, так и M на элементы N1.A.

пример конца

Using_static_directive специально не импортирует методы расширения непосредственно как статические методы, но делает их доступными для вызова метода расширения (§12.8.9.3).

Пример:

namespace N1 
{
    static class A 
    {
        public static void M(this string s){}
    }
}

namespace N2
{
    using static N1.A;

    class B
    {
        void N()
        {
            M("A");      // Error, M unknown
            "B".M();     // Ok, M known as extension method
            N1.A.M("C"); // Ok, fully qualified
        }
    }
}

using_static_directive импортирует метод расширения, содержащийся вN1.A, но только в качестве метода M расширения. Таким образом, первая ссылка M на текст результатов в результате ошибки во время компиляции B.N , так как именованные M элементы не находятся в области.

пример конца

Using_static_directive импортирует только элементы и типы, объявленные непосредственно в данном типе, а не члены и типы, объявленные в базовых классах.

Пример:

namespace N1 
{
    class A 
    {
        public static void M(string s){}
    }

    class B : A
    {
        public static void M2(string s){}
    }
}

namespace N2
{
    using static N1.B;

    class C
    {
        void N()
        {
            M2("B");      // OK, calls B.M2
            M("C");       // Error. M unknown 
        }
    }
}

using_static_directive импортирует метод, содержащийся вN1.B, но не импортирует M методM2, содержащийся в N1.A. Таким образом, ссылка на M текст результатов в результате ошибки во время компиляции C.N , так как именованные M элементы не находятся в области. Разработчики должны добавить вторую using static директиву, чтобы указать, что методы в N1.A ней также должны быть импортированы.

пример конца

Неоднозначность между несколькими using_namespace_directives и using_static_directives рассматриваются в разделе 14.5.3.

Объявления членов пространства имен 14.6

Namespace_member_declaration — это namespace_declaration (§14.3) или type_declaration (§14.7).

namespace_member_declaration
    : namespace_declaration
    | type_declaration
    ;

Единица компиляции или тело пространства имен может содержать namespace_member_declarations, и такие объявления вносят новые члены в базовое пространство объявлений содержащего единицы компиляции или тела пространства имен.

Объявления типов 14.7

Type_declaration — это class_declaration (§15.2), struct_declaration (§16.2), interface_declaration (§18.2), enum_declaration (§19.2) или delegate_declaration (§20.2).

type_declaration
    : class_declaration
    | struct_declaration
    | interface_declaration
    | enum_declaration
    | delegate_declaration
    ;

Type_declaration может возникать в виде объявления верхнего уровня в единице компиляции или в виде объявления члена в пространстве имен, классе или структуре.

Если объявление типа для типа происходит в виде объявления верхнего уровня в единице компиляции, полное имя (§7.8.2) объявления типа T совпадает с неквалифицированным именем объявления (§7.8.2). Если объявление типа для типа T происходит в пространстве имен, классе или объявлении структуры, полное имя (§7.8.3) объявления S.Nтипа, где S является полное имя содержащего пространства имен, класса или объявления структуры, а также N является неквалифицированным именем объявления.

Тип, объявленный в классе или структуре, называется вложенным типом (§15.3.9).

Модификаторы разрешенного доступа и доступ по умолчанию для объявления типа зависят от контекста, в котором происходит объявление (§7.5.2):

  • Типы, объявленные в единицах компиляции или пространствах имен, могут иметь public или internal получать доступ. По умолчанию используется internal доступ.
  • Типы, объявленные в классах, могут иметь public, protected internal, protected, private protectedinternalили private доступ. По умолчанию используется private доступ.
  • Типы, объявленные в структуры, могут иметь publicinternalили private получить доступ. По умолчанию используется private доступ.

14.8 Квалифицированный псевдоним

14.8.1 Общие

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

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

qualified_alias_member
    : identifier '::' identifier type_argument_list?
    ;

Qualified_alias_member можно использовать в качестве namespace_or_type_name (§7.8) или в качестве левого операнда в member_access (§12.8.7).

Qualified_alias_member состоит из двух идентификаторов, называемых идентификаторами слева и правой рукой, разделяемым :: маркером и при необходимости type_argument_list. Если идентификатор слева является глобальным, глобальный пространство имен выполняется поиск правого идентификатора. Для любого другого левого идентификатора этот идентификатор выглядит как экстерн или использует псевдоним (§14.4 и §14.5.2). Ошибка во время компиляции возникает, если такой псевдоним отсутствует или псевдоним ссылается на тип. Если псевдоним ссылается на пространство имен, то для этого пространства имен выполняется поиск правого идентификатора.

Qualified_alias_member имеет одну из двух форм:

  • N::I<A₁, ..., Aₑ>, где N и I представляет идентификаторы и <A₁, ..., Aₑ> является списком аргументов типа. (e всегда один.)
  • N::I, где N и I представляет идентификаторы. (В этом случае e считается нулевой.)

Используя эту нотацию, значение qualified_alias_member определяется следующим образом:

  • Если N это идентификатор global, то глобальное пространство имен выполняется поиск по следующим причинам I:
    • Если глобальное пространство имен содержит пространство имен и I e равно нулю, то qualified_alias_member ссылается на это пространство имен.
    • В противном случае, если глобальное пространство имен содержит не I универсальный тип и e равно нулю, то qualified_alias_member ссылается на этот тип.
    • В противном случае, если глобальное пространство имен содержит тип с I e параметрами типа, то qualified_alias_member ссылается на этот тип, созданный с заданными аргументами типа.
    • В противном случае qualified_alias_member не определен и возникает ошибка во время компиляции.
  • В противном случае, начиная с объявления пространства имен (§14.3) сразу же, содержащего qualified_alias_member (если таковые есть), продолжая каждое объявление пространства имен (если таковые имеются) и заканчивая единицей компиляции, содержащей qualified_alias_member, следующие действия оцениваются до тех пор, пока сущность не будет найдена:
    • Если объявление пространства имен или единица компиляции содержит using_alias_directive, которая связывает N с типом, qualified_alias_member не определена и возникает ошибка во время компиляции.
    • В противном случае, если объявление пространства имен или единица компиляции содержит extern_alias_directive или using_alias_directive, которая связывается N с пространством имен, то:
      • Если пространство имен, связанное с N ним, содержит имя пространства I имен и e равно нулю, то qualified_alias_member ссылается на это пространство имен.
      • В противном случае, если пространство именI, связанное с N ним, содержит не универсальный тип и e равно нулю, то qualified_alias_member ссылается на этот тип.
      • В противном случае, если пространство имен, связанное с N ним, содержит тип с e I параметрами типа, то qualified_alias_member ссылается на этот тип, созданный с заданными аргументами типа.
      • В противном случае qualified_alias_member не определен и возникает ошибка во время компиляции.
  • В противном случае qualified_alias_member не определен и возникает ошибка во время компиляции.

Пример. В коде:

using S = System.Net.Sockets;

class A
{
    public static int x;
}

class C
{
    public void F(int A, object S)
    {
        // Use global::A.x instead of A.x
        global::A.x += A;
        // Use S::Socket instead of S.Socket
        S::Socket s = S as S::Socket;
    }
}

Класс ссылается на этот классA, а тип System.Net.Sockets.Socket ссылается на S::Socket.global::A Использование A.x и S.Socket вместо этого приводило бы к ошибкам во время компиляции, так как A и S было бы разрешено к параметрам.

пример конца

Примечание. Идентификатор global имеет особое значение, только если используется в качестве левого идентификатора qualified_alias_name. Это не ключевое слово, и это не сам псевдоним; это контекстное ключевое слово (§6.4.4). В коде:

class A { }

class C
{
    global.A x; // Error: global is not defined
    global::A y; // Valid: References A in the global namespace
}

использование global.A вызывает ошибку во время компиляции, так как в области нет сущности, именуемой global . Если бы некоторые сущности с именем global были в области, то global в global.A этом объекте было бы разрешено.

Использование global в качестве левого идентификатора qualified_alias_member всегда приводит к поиску в global пространстве имен, даже если используется псевдоним.global В коде:

using global = MyGlobalTypes;

class A { }

class C 
{
    global.A x; // Valid: References MyGlobalTypes.A
    global::A y; // Valid: References A in the global namespace
}

global.A разрешает и MyGlobalTypes.A global::A разрешает класс A в глобальном пространстве имен.

конечная заметка

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

Каждый блок компиляции и текст пространства имен имеет отдельное пространство объявлений для экстерн-псевдонимов и использование псевдонимов. Таким образом, в то время как имя экстерн-псевдонима или псевдонима должно быть уникальным в наборе экстерн-псевдонимов и использовать псевдонимы, объявленные в немедленном элементе компиляции или теле пространства имен, псевдоним может иметь то же имя, что и тип или пространство имен, если он используется только с квалификатором :: .

Пример. В следующем примере:

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 ищется только в качестве псевдонима пространства имен.

пример конца