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


Глобальная директива использования

Заметка

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