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


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 (§23.3) единицы компиляции позволяют спецификации атрибутов целевой сборки и модуля. Сборки и модули служат физическими контейнерами для типов. Сборка может состоять из нескольких физически отдельных модулей.

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

Example:

// 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_directives должны отображаться перед объявлениями членов.

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

Example:

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

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

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

конечный пример

Пространства имен открыты, и два объявления пространства имен с одинаковым полным именем (§7.8.3) вносят вклад в одно и то же пространство объявлений (§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_names (§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_directive. Таким образом, одноранговые 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 , можно использовать для ссылки на заданное пространство имен или тип.

Example:

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

    class B: A {}
}

Выше в объявлениях членов в N3 пространстве имен используется псевдоним, Aпоэтому класс N1.N2.A является производным от классаN3.BN1.N2.A. Тот же эффект можно получить путем создания псевдонима 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. Идентификатор директивы псевдонима должен быть уникальным в соответствующем пространстве объявления псевдонима. Идентификатор псевдонима не должен быть уникальным в пределах глобального пространства объявлений или пространства объявления соответствующего пространства имен.

Example:

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тел пространства имен и единиц компиляции, заключающих ее. Это может привести к тому, что один и тот же идентификатор имеет разные значения в разных частях.

Example:

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
    }
}

конечный пример

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

Example:

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

Example:

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 , скрыты аналогичными именованными элементами в блоке компиляции или тексте пространства имен.

Example:

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 считаются неоднозначными.

Example:

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, доступные вложенные типы и статические члены (кроме методов расширения), содержащиеся непосредственно в объявлении данного типа, можно ссылаться напрямую.

Example:

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.10.3).

Example:

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

конечный пример

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

Example:

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 импортирует метод, содержащийся вM2, но не импортирует метод N1.BM, содержащийся в 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_declaration19.2), enum_declaration20.2) или delegate_declaration21.2).

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

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

Когда объявление типа для типа происходит в виде объявления верхнего уровня в единице компиляции, полное имя (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:
    • Если глобальное пространство имен содержит пространство имен и Ie равно нулю, то qualified_alias_member ссылается на это пространство имен.
    • В противном случае, если глобальное пространство имен содержит не универсальный тип с именем I и e равно нулю, то qualified_alias_member ссылается на этот тип.
    • В противном случае, если глобальное пространство имен содержит тип с Ie параметрами типа, то 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 ним, содержит пространство имен и Ie равно нулю, то qualified_alias_member ссылается на это пространство имен.
      • В противном случае, если пространство именN, связанное с I ним, содержит не универсальный тип и e равно нулю, то qualified_alias_member ссылается на этот тип.
      • В противном случае, если пространство имен, связанное с N ним, содержит тип с Ie параметрами типа, то 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, а тип global::A ссылается на System.Net.Sockets.Socket.S::Socket Использование 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.Aglobal::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 ищется только в качестве псевдонима пространства имен.

конечный пример