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.A
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. Идентификатор директивы псевдонима должен быть уникальным в соответствующем пространстве объявления псевдонима. Идентификатор псевдонима не должен быть уникальным в пределах глобального пространства объявлений или пространства объявления соответствующего пространства имен.
Пример:
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 protected
internal
илиprivate
доступ. По умолчанию используетсяprivate
доступ. - Типы, объявленные в структуры, могут иметь
public
internal
или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
ищется только в качестве псевдонима пространства имен.пример конца
ECMA C# draft specification