Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
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; аналогично.AN3.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_declaration (§19.2), enum_declaration (§20.2) или delegate_declaration (§21.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ищется только в качестве псевдонима пространства имен.конечный пример
ECMA C# draft specification