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


Пространства имен с областью действия файла

Заметка

Эта статья является спецификацией компонентов. Спецификация служит проектным документом для функции. Она включает предлагаемые изменения спецификации, а также информацию, необходимую во время проектирования и разработки функции. Эти статьи публикуются до тех пор, пока предложенные изменения спецификации не будут завершены и включены в текущую спецификацию ECMA.

Может возникнуть некоторое несоответствие между спецификацией компонентов и завершенной реализацией. Эти различия фиксируются в соответствующих собраниях по проектированию языка (LDM).

Дополнительные сведения о процессе внедрения спецификаций функций в стандарт языка C# см. в статье о спецификациях .

Проблема чемпиона: https://github.com/dotnet/csharplang/issues/137

Сводка

Пространства имен с областью действия файлов используют менее подробный формат для типичного случая файлов, содержащих только одно пространство имен. Формат пространства имен с областью действия файла namespace X.Y.Z; (обратите внимание на точку с запятой и отсутствие фигурных скобок). Это позволяет использовать такие файлы, как показано ниже.

namespace X.Y.Z;

using System;

class X
{
}

Семантика заключается в том, что использование формы namespace X.Y.Z; эквивалентно написанию namespace X.Y.Z { ... }, где оставшаяся часть файла после пространства имен, ограниченного областью действия файла, находится в разделе ... объявления стандартного пространства имен.

Мотивация

Анализ экосистемы C# показывает, что примерно 99,7% файлы являются одним из следующих форм:

namespace X.Y.Z
{
    // usings

    // types
}

или

// usings

namespace X.Y.Z
{
    // types
}

Однако обе эти формы вынуждают пользователя делать отступы для большей части своего кода и добавлять значительное количество лишних действий для того, что по сути является очень базовой концепцией. Это влияет на ясность, использование горизонтального и вертикального пространства и часто является неудовлетворительным для пользователей, привыкших к C# и приходящих с других языков (где обычно меньше формальностей).

Основная цель этой функции состоит в том, чтобы удовлетворить потребности основной части экосистемы с меньшим количеством ненужного кода.

Подробный дизайн

Это предложение принимает форму диффа к существующим единицам компиляции (§14.2) спецификации.

Дифф

compilation_unit определяет общую структуру исходного файла. Единица компиляции состоит из нуля или более using_directive, затем следует ноль или более global_attributes, затем следует ноль или более namespace_member_declaration.

compilation_unit определяет общую структуру исходного файла. Единица компиляции состоит из нуля или более using_directive, затем нуля или более global_attributes, и затем compilation_unit_body. compilation_unit_body может быть file_scoped_namespace_declaration или нулевым или более оператороми namespace_member_declaration.

compilation_unit
~~    : extern_alias_directive* using_directive* global_attributes? namespace_member_declaration*~~
    : extern_alias_directive* using_directive* global_attributes? compilation_unit_body
    ;

compilation_unit_body
    : statement* namespace_member_declaration*
    | file_scoped_namespace_declaration
    ;

... неизменившийся...

file_scoped_namespace_declaration будет определять членов, соответствующих namespace_declaration, которому она семантически эквивалентна. Дополнительные сведения см. в разделе (Объявления пространства имен).

Объявления пространства имен

namespace_declaration состоит из ключевого слова namespace, за которым следует имя пространства имен и текст, за которым при необходимости следует точка с запятой. file_scoped_namespace_declaration состоит из ключевого слова namespace, за которым следует имя пространства имен, точка с запятой и необязательный список extern_alias_directives, using_directives и type_declaration.

namespace_declaration
    : 'namespace' qualified_identifier namespace_body ';'?
    ;
    
file_scoped_namespace_declaration
    : 'namespace' qualified_identifier ';' extern_alias_directive* using_directive* type_declaration*
    ;

... unchanged ...

... неизменившийся...

Два объявления пространства имен, приведенные выше, относятся к одному и тому же пространству деклараций, в данном случае описывая два класса с полными именами N1.N2.A и N1.N2.B. Так как два объявления способствуют одному и тому же пространству объявлений, это было бы ошибкой, если каждая из них содержала объявление члена с одинаковым именем.

file_scoped_namespace_declaration позволяет записывать объявление пространства имен без блока { ... }. Например:

extern alias A;
namespace Name;
using B;
class C
{
}

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

extern alias A;
namespace Name
{
    using B;
    class C
    {
    }
}

В частности, file_scoped_namespace_declaration обрабатывается так же, как namespace_declaration в том же месте в compilation_unit с тем же qualified_identifier. extern_alias_directive, using_directiveи type_declarationэтого file_scoped_namespace_declaration действуют так же, как если бы они были объявлены в том порядке внутри namespace_body этого namespace_declaration.

Исходный файл не может содержать как file_scoped_namespace_declaration, так и namespace_declaration. Исходный файл не может содержать несколько file_scoped_namespace_declarations. compilation_unit не может содержать как file_scoped_namespace_declaration, так и любые инструкции верхнего уровня. type_declarations не может предшествовать file_scoped_namespace_declaration.

Псевдонимы extern (внешние)

... неизменившийся...