Глобальная директива использования
Заметка
Эта статья является спецификацией компонентов. Спецификация служит проектным документом для функции. Она включает предлагаемые изменения спецификации, а также информацию, необходимую во время дизайна и разработки функции. Эти статьи публикуются до тех пор, пока предложенные изменения спецификации не будут завершены и включены в текущую спецификацию ECMA.
Может возникнуть некоторое несоответствие между спецификацией компонентов и завершенной реализацией. Эти различия фиксируются в соответствующих совещаниях по разработке языка (LDM).
Дополнительные сведения о процессе внедрения спецификаций функций в стандарт языка C# см. в статье о спецификациях .
Вопрос чемпиона: https://github.com/dotnet/csharplang/issues/3428
Синтаксис директивы using расширен с помощью необязательного ключевого слова global
, которое может предшествовать ключевому слову using
:
compilation_unit
: extern_alias_directive* global_using_directive* using_directive* global_attributes? namespace_member_declaration*
;
global_using_directive
: global_using_alias_directive
| global_using_namespace_directive
| global_using_static_directive
;
global_using_alias_directive
: 'global' 'using' identifier '=' namespace_or_type_name ';'
;
global_using_namespace_directive
: 'global' 'using' namespace_name ';'
;
global_using_static_directive
: 'global' 'using' 'static' type_name ';'
;
- global_using_directiveразрешены только на уровне единицы компиляции (нельзя использовать внутри namespace_declaration).
- global_using_directives, если таковые имеются, должны предшествовать любым using_directive.
- Область действия global_using_directiveраспространяется на namespace_member_declarationвсех единиц компиляции в программе. Область применения global_using_directive в частности не включает другие global_using_directive. Таким образом, одноранговые global_using_directiveили аналогичные из другой единицы компиляции не влияют друг на друга, а порядок, в котором они записаны, не имеет значения. Область действия global_using_directive в частности не включает using_directiveсразу же, содержащихся в любой единице компиляции программы.
Эффект добавления global_using_directive в программу можно рассматривать как эффект добавления аналогичной using_directive, которая разрешается к тому же целевому пространству имен или типу в каждую единицу компиляции программы. Однако целевая директива global_using_directive разрешается в контексте единицы компиляции, содержащей её.
области §7.7
Это соответствующие пункты маркера с предлагаемыми дополнениями (которые полужирным шрифтом):
- Область видимости имени, определяемая extern_alias_directive, охватывает global_using_directives,using_directives, global_attributes и namespace_member_declarationв его непосредственном блоке компиляции или теле пространства имен. extern_alias_directive не вносит новых членов в базовое пространство объявлений. Другими словами, extern_alias_directive не является транзитивным, но, скорее, влияет только на модуль компиляции или тело пространства имен, в котором она происходит.
- Область действия имени, заданного или импортированного с помощью global_using_directive, распространяется на global_attributes и namespace_member_declarationво всех compilation_unitпрограммы.
§7.8 пространства имен и имен типов
В алгоритм, определяющий значение namespace_or_type_name, вносятся изменения следующим образом.
Это соответствующий пункт списка с предлагаемыми дополнениями (которые выделенные жирным шрифтом):
- Если namespace_or_type_name имеет форму
I
или имеет формуI<A1, ..., Ak>
:- Если
K
равно нулю, а namespace_or_type_name отображается в объявлении универсального метода (§15.6) и если это объявление включает параметр типа (§15.2.3) с именемI
, то namespace_or_type_name ссылается на этот параметр типа. - В противном случае, если namespace_or_type_name встречается в объявлении типа, то для каждого типа экземпляра
T
(§15.3.2), начиная с типа экземпляра этого объявления и продолжая с типом экземпляра каждого окружающего класса или структуры (если таковой имеется):- Если
K
равно нулю, а объявлениеT
включает параметр типа с именемI
, то namespace_or_type_name ссылается на этот параметр типа. - В противном случае, если namespace_or_type_name появляется в теле объявления типа, и
T
или любой из его базовых типов содержит вложенный доступный тип с именемI
и параметрами типаK
, то namespace_or_type_name относится к этому типу, построенному с заданными аргументами типа. Если существует несколько таких типов, выбирается тип, объявленный в более производном типе. Обратите внимание, что элементы без типов (константы, поля, методы, свойства, индексаторы, операторы, конструкторы экземпляров, деструкторы и статические конструкторы) и элементы типов с другим числом параметров типа игнорируются при определении значения namespace_or_type_name.
- Если
- Если предыдущие шаги были неудачными, для каждого пространства имен
N
, начиная с пространства имен, в котором находится namespace_or_type_name, продолжая с каждым вложенным пространством имен (если есть), и заканчивая глобальным пространством имен, следующие шаги выполняются до тех пор, пока не будет найдена сущность:- Если
K
равно нулю, аI
— имя пространства имен вN
, то:- Если расположение, в котором происходит namespace_or_type_name, заключено объявлением пространства имен для
N
, а объявление пространства имен содержит extern_alias_directive или using_alias_directive, которое связывает имяI
с пространством имен или типом, или любым объявлением пространства имен дляN
в программе содержит global_using_alias_directive, которая связывает имяI
с пространством имен или типом, затем namespace_or_type_name неоднозначно и возникает ошибка во время компиляции. - В противном случае namespace_or_type_name ссылается на пространство имен с именем
I
вN
.
- Если расположение, в котором происходит namespace_or_type_name, заключено объявлением пространства имен для
- В противном случае, если
N
содержит доступный тип с именемI
и параметрами типаK
, то:- Если
K
равно нулю, а расположение, в котором происходит namespace_or_type_name, заключено объявлением пространства имен дляN
, а объявление пространства имен содержит extern_alias_directive или using_alias_directive, которое связывает имяI
с пространством имен или типом, или объявлением пространства имен дляN
в программе содержит global_using_alias_directive, который связывает имяI
с пространство имен или тип, тогда namespace_or_type_name неоднозначно и возникает ошибка во время компиляции. - В противном случае namespace_or_type_name ссылается на тип, созданный с заданными аргументами типа.
- Если
- В противном случае, если место, в котором встречается namespace_or_type_name, находится внутри объявления пространства имен для
N
:- Если
K
равно нулю, а объявление пространства имен содержит extern_alias_directive или using_alias_directive, которое связывает имяI
с импортированным пространством имен или типом, или любое объявление пространства имен дляN
в программе содержит global_using_alias_directive, которая связывает имяI
с импортированным пространством имен или типом, затем namespace_or_type_name ссылается на это пространство имен или тип. - В противном случае, если пространства имен и объявления типов, импортируемые директивами using_namespace_directiveи using_alias_directiveвнутри объявления пространства имен , а также пространства имен и объявления типов, импортируемые директивами global_using_namespace_directiveи global_using_static_directiveиз любого объявления пространства имен для
N
в программе, содержат ровно один доступный тип с именемI
иK
параметрами типа, то namespace_or_type_name ссылается на этот тип, созданный с заданными аргументами типа. - В противном случае, если пространства имен и объявления типов, импортированные директивами using_namespace_directiveи using_alias_directiveв объявлении пространства имен , а также пространствами имен и объявлениями типов, импортированными директивами global_using_namespace_directiveи global_using_static_directiveлюбого объявления пространства имен для
N
в программе, содержат более одного доступного типа с именемI
и параметрами типаK
, то namespace_or_type_name является неоднозначным, и возникает ошибка.
- Если
- Если
- В противном случае namespace_or_type_name не определен и возникает ошибка во время компиляции.
- Если
Простые имена §12.8.4
Изменения вносятся в правила оценки simple_name следующим образом.
Это соответствующая точка маркера с предлагаемыми дополнениями (которые в полужирном):
- В противном случае, для каждого пространства имен
N
, начиная с пространства имен, в котором встречается simple_name, продолжая с каждым внешним пространством имен (если таковое имеется) и заканчивая глобальным пространством имен, следующие шаги выполняются до тех пор, пока не будет найдена сущность:- Если
K
равно нулю, аI
— имя пространства имен вN
, то:- Если расположение, в котором происходит simple_name, заключено объявлением пространства имен для
N
, а объявление пространства имен содержит extern_alias_directive или using_alias_directive, которое связывает имяI
с пространством имен или типом, или любое объявление пространства имен дляN
в программе содержит global_using_alias_directive, которое связывает имяI
с пространством имен или типом, то simple_name является неоднозначным, и возникает ошибка компиляции. - В противном случае simple_name ссылается на пространство имен под названием
I
вN
.
- Если расположение, в котором происходит simple_name, заключено объявлением пространства имен для
- В противном случае, если
N
содержит доступный тип с именемI
и параметрами типаK
, то:- Если
K
равно нулю, а расположение, в котором происходит simple_name, заключено объявлением пространства имен дляN
, а объявление пространства имен содержит extern_alias_directive или using_alias_directive, которое связывает имяI
с пространством имен или типом, или любое объявление пространства имен дляN
в программе содержит global_using_alias_directive, которая связывает имяI
с пространством имен или тип, затем simple_name неоднозначно и возникает ошибка во время компиляции. - В противном случае namespace_or_type_name ссылается на тип, созданный с заданными аргументами типа.
- Если
- В противном случае, если simple_name прописывается в области действия пространства имен для
N
:- Если
K
равно нулю, а объявление пространства имен содержит extern_alias_directive или using_alias_directive, которое связывает имяI
с импортированным пространством имен или типом, или любое объявление пространства имен дляN
в программе содержит global_using_alias_directive, которая связывает имяI
с импортированным пространством имен или типом, затем simple_name ссылается на это пространство имен или тип. - В противном случае, если пространства имен и объявления типов импортируются с помощью using_namespace_directiveи using_static_directiveв объявлении пространства имен , а также пространства имен и объявления типов, импортируемые с помощью global_using_namespace_directiveи global_using_static_directiveлюбого объявления пространства имен для
N
в программе, содержат ровно один доступный тип или нерасширяемый статический член с именемI
и параметрами типаK
, то simple_name ссылается на этот тип или член, созданный с заданными аргументами типа. - В противном случае, если пространства имен и типы, импортированные using_namespace_directiveобъявления пространства имен , а также пространства имен и объявления типов, импортированные global_using_namespace_directiveи global_using_static_directiveлюбого объявления пространства имен для
N
в программе, содержат более чем один доступный тип или статического члена, не являющегося методом расширения, с именемI
и параметрами типаK
, то simple_name является неоднозначным, и возникает ошибка.
- Если
- Если
Вызовы метода расширения §12.8.10.3
В алгоритм вносятся изменения, чтобы следующим образом найти наилучшую type_nameC
.
Это соответствующая точка маркера с предлагаемыми дополнениями (которые в полужирном):
- Начиная с ближайшего объявления пространства имен, последовательно проходя через каждое включающее пространство имен и завершая поиски в содержащем блоке компиляции, делаются последовательные попытки найти набор методов расширения.
- Если заданное пространство имен или единица компиляции напрямую содержит объявления не универсальных типов
Ci
с соответствующими методами расширенияMj
, то набор этих методов расширения является набором кандидатов. - Если типы
Ci
импортированы с помощью using_static_declarations и непосредственно объявлены в пространствах имен, импортируемых с помощью using_namespace_directiveв заданном пространстве имен или в единице компиляции , и если достигается при использовании global_using_static_declarations и непосредственно объявленных в пространствах имен, импортируемых с помощью global_using_namespace_directiveв программе, непосредственно содержат допустимые методы расширенияMj
, то набор этих методов расширения является набором кандидатов.
- Если заданное пространство имен или единица компиляции напрямую содержит объявления не универсальных типов
Единицы компиляции §14.2
compilation_unit определяет общую структуру исходного файла. Единица компиляции состоит из ноль или более global_using_directiveс ноль или более using_directive, за которым следует ноль или более global_attributes, за которым следует ноль или более namespace_member_declarations.
compilation_unit
: extern_alias_directive* global_using_directive* using_directive* global_attributes? namespace_member_declaration*
;
Программа C# состоит из одного или нескольких единиц компиляции, каждый из которых содержится в отдельном исходном файле. При компиляции программы C# все единицы компиляции обрабатываются вместе. Таким образом, единицы компиляции могут зависеть друг от друга, возможно, в циклической форме.
global_using_directiveединицы компиляции влияют на global_attributes и namespace_member_declarationвсех единиц компиляции в программе.
Псевдонимы extern §14.4
Область extern_alias_directive распространяется на global_using_directive,using_directive, global_attributes и namespace_member_declarationв пределах его непосредственного компиляционного блока или тела пространства имен.
Использование директив псевдонима §14.5.2
Порядок записи using_alias_directiveне имеет значения, а разрешение namespace_or_type_name, на которое ссылается using_alias_directive, не влияет на сам using_alias_directive или другие using_directiveв немедленном тексте единицы компиляции или пространства имен. и, если using_alias_directive немедленно содержится в единице компиляции, не затрагивается global_using_directiveв программе. Иными словами, namespace_or_type_nameusing_alias_directive разрешается как будто непосредственно содержащий модуль компиляции или тело пространства имен не содержало using_directive, и, если using_alias_directive непосредственно содержится в единице компиляции, программа не имела global_using_directive. Однако на using_alias_directive могут повлиять extern_alias_directiveв непосредственном блоке компиляции или тексте пространства имен.
Директивы глобального использования псевдонимов
global_using_alias_directive вводит идентификатор, который служит в качестве псевдонима для пространства имен или типа в программе.
global_using_alias_directive
: 'global' 'using' identifier '=' namespace_or_type_name ';'
;
В объявлениях членов в любой единице компиляции программы, содержащей global_using_alias_directive, идентификатор, представленный global_using_alias_directive, можно использовать для ссылки на заданное пространство имен или тип.
Идентификатор директивы global_using_alias_directive должен быть уникальным в пределах пространства объявлений любой единицы компиляции программы, содержащей директиву global_using_alias_directive.
Как и обычные члены, имена, представленные global_using_alias_directive, скрыты аналогично именованными элементами во вложенных областях.
Порядок, в котором записываются global_using_alias_directive, не имеет значения, и разрешение namespace_or_type_name, на которое ссылается global_using_alias_directive, не зависит ни от самого global_using_alias_directive, ни от других global_using_directiveили using_directiveв программе. Иными словами, namespace_or_type_nameglobal_using_alias_directive разрешается так, как если бы непосредственно содержащий модуль компиляции был без using_directives, а вся содержащая программа была без global_using_directives. Однако на global_using_alias_directive могут повлиять extern_alias_directiveв непосредственном блоке компиляции.
global_using_alias_directive может создать псевдоним для любого пространства имен или типа.
Доступ к пространству имен или типу с помощью псевдонима дает точно тот же результат, что и доступ к пространству имен или типу через объявленное имя.
Используя псевдонимы, можно обозначить закрытый конструированный тип, но нельзя обозначить объявление обобщенного типа без указания аргументов типа.
Глобальные директивы пространства имен
global_using_namespace_directive импортирует типы из пространства имен в программу, позволяя использовать идентификатор каждого типа без необходимости указания квалификации.
global_using_namespace_directive
: 'global' 'using' namespace_name ';'
;
В объявлениях членов в программе, содержащей global_using_namespace_directive, можно ссылаться непосредственно на типы, содержащиеся в заданном пространстве имен.
global_using_namespace_directive импортирует типы, содержащиеся в заданном пространстве имен, но в частности не импортирует вложенные пространства имен.
В отличие от global_using_alias_directive, global_using_namespace_directive может импортировать типы, идентификаторы которых уже определены в единице компиляции программы. Фактически, в заданной единице компиляции имена, импортированные любым global_using_namespace_directive в программе, скрыты аналогично именованными элементами в единице компиляции.
Если несколько пространств имен или типов, импортированных global_using_namespace_directiveили global_using_static_directiveв одной программе, содержат типы по одному type_name имени, ссылки на это имя считаются неоднозначными.
Кроме того, если несколько пространств имен или типов, импортированных global_using_namespace_directiveили global_using_static_directiveв той же программе, содержат типы или члены с одинаковыми именами, ссылки на это имя как simple_name считаются неоднозначными.
namespace_name, на который ссылается global_using_namespace_directive, определяется тем же образом, что и namespace_or_type_name, на который ссылается global_using_alias_directive. Таким образом, global_using_namespace_directiveв одной программе не влияют друг на друга и могут быть записаны в любом порядке.
Глобальное использование статических директив
global_using_static_directive импортирует вложенные типы и статические члены, содержащиеся непосредственно в объявлении типа, в содержащую программу, что позволяет использовать идентификатор каждого члена и типа без квалификации.
global_using_static_directive
: 'global' 'using' 'static' type_name ';'
;
В объявлениях членов программы, содержащей global_using_static_directive, можно использовать напрямую доступные вложенные типы и статические члены (кроме методов расширения), содержащиеся непосредственно в объявлении данного типа.
global_using_static_directive специально не импортирует методы расширения непосредственно как статические методы, но делает их доступными для вызова метода расширения.
global_using_static_directive импортирует только элементы и типы, объявленные непосредственно в данном типе, а не члены и типы, объявленные в базовых классах.
Неоднозначность между несколькими global_using_namespace_directiveи global_using_static_directives рассматриваются в разделе global_using_namespace_directive(выше).
Квалифицированный участник псевдонима §14.8
В алгоритм, определяющий значение qualified_alias_member, вносятся изменения следующим образом.
Это соответствующий пункт списка с предлагаемыми дополнениями, которые выделены полужирным шрифтом.
В противном случае, начиная с объявления пространства имен (§14.3), непосредственно содержащего qualified_alias_member (если он существует), затем охватывая каждое следующее объявление пространства имен (если они существуют) и заканчивая единицей компиляции, содержащей qualified_alias_member, оцениваются следующие шаги до тех пор, пока не будет найдена сущность:
- Если объявление пространства имен или единица компиляции содержит using_alias_directive, которая связывает
N
с типом, или когда достигается единица компиляции, программа содержит global_using_alias_directive, которая связываетN
с типом, не определена qualified_alias_member и возникает ошибка во время компиляции. - В противном случае, если объявление пространства имен или единица компиляции содержит extern_alias_directive или using_alias_directive, которая связывает
N
с пространством имен, *или при достижении единицы компиляции программа содержит global_using_alias_directive, которая связываетN
с пространством имен, затем:- Если пространство имен, связанное с
N
, содержит пространство имен с именемI
иK
равно нулю, то qualified_alias_member ссылается на это пространство имен. - В противном случае, если пространство имен, связанное с
N
, содержит не универсальный тип с именемI
иK
равно нулю, то qualified_alias_member ссылается на этот тип. - В противном случае, если пространство имен, связанное с
N
, содержит тип с именемI
с параметрами типаK
, то qualified_alias_member ссылается на этот тип, созданный с заданными аргументами типа. - В противном случае qualified_alias_member не определен и возникает ошибка во время компиляции.
- Если пространство имен, связанное с
- Если объявление пространства имен или единица компиляции содержит using_alias_directive, которая связывает
C# feature specifications