Compartilhar via


Namespaces com escopo de arquivo

Observação

Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ela inclui alterações de especificação propostas, juntamente com as informações necessárias durante o design e o desenvolvimento do recurso. Esses artigos são publicados até que as alterações de especificação propostas sejam finalizadas e incorporadas na especificação ECMA atual.

Pode haver algumas divergências entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da reunião de design de idioma (LDM).

Você pode saber mais sobre o processo de adoção de speclets de recursos no padrão de linguagem C# no artigo sobre as especificações de .

Problema do especialista: https://github.com/dotnet/csharplang/issues/137

Resumo

Namespaces com escopo de arquivo utilizam um formato mais conciso para o caso típico de arquivos que contêm apenas um namespace. O formato de namespace com escopo de arquivo é namespace X.Y.Z; (observe o ponto e vírgula e a falta de chaves). Isso permite arquivos como os seguintes:

namespace X.Y.Z;

using System;

class X
{
}

A semântica é que o uso da forma namespace X.Y.Z; é equivalente a escrever namespace X.Y.Z { ... }, onde o restante do arquivo após o namespace com escopo de arquivo está na seção ... de uma declaração de namespace padrão.

Motivação

A análise do ecossistema C# mostra que aproximadamente 99,7% dos arquivos são de um destes formatos:

namespace X.Y.Z
{
    // usings

    // types
}

or

// usings

namespace X.Y.Z
{
    // types
}

No entanto, essas duas formas forçam o usuário a indentar a maior parte de seu código e a adicionar uma quantidade considerável de formalidades para o que é, efetivamente, um conceito muito básico. Isso afeta a clareza, usa espaço horizontal e vertical e geralmente é insatisfatório para usuários acostumados ao C# e aqueles que vêm de outras linguagens de programação (que geralmente têm menos formalidade aqui).

O objetivo principal do recurso, portanto, é atender às necessidades da maioria do ecossistema com menos clichês desnecessários.

Projeto detalhado

Esta proposta toma a forma de um diff para a seção de unidades de compilação existentes (§14.2) da especificação.

Diff

Um compilation_unit define a estrutura geral de um arquivo de origem. Uma unidade de compilação consiste em zero ou mais using_directives, seguidos por zero ou mais global_attributes e seguidos por zero ou mais namespace_member_declarations.

Um compilation_unit define a estrutura geral de um arquivo de origem. Uma unidade de compilação consiste em zero ou mais using_directives , seguidos por zero ou mais global_attributes, seguidos por um compilation_unit_body. Um compilation_unit_body pode ser uma file_scoped_namespace_declaration ou zero ou mais instruções e namespace_member_declarations.

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
    ;

... inalterado ...

Uma file_scoped_namespace_declaration contribuirá com membros correspondentes à namespace_declaration à qual é semanticamente equivalente. Consulte (Declarações de namespace) para obter mais detalhes.

Declarações de namespace

Uma namespace_declaration consiste na palavra-chave namespace, seguida por um nome de namespace e corpo, opcionalmente seguido por um ponto e vírgula. Uma file_scoped_namespace_declaration consiste na palavra-chave namespace, seguida por um nome de namespace, um ponto e vírgula e uma lista opcional de extern_alias_directives, using_directives e type_declarations.

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

... unchanged ...

... inalterado ...

as duas declarações de namespace acima contribuem para o mesmo espaço de declaração, neste caso declarando duas classes com nomes N1.N2.A e N1.N2.B totalmente qualificados. Como as duas declarações contribuem para o mesmo espaço de declaração, seria um erro se cada uma contivesse uma declaração de um membro com o mesmo nome.

Um file_scoped_namespace_declaration permite que uma declaração de namespace seja feita sem o bloco { ... }. Por exemplo:

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

é semanticamente equivalente a

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

Especificamente, uma file_scoped_namespace_declaration é tratada da mesma forma que uma namespace_declaration no mesmo local no compilation_unit com o mesmo qualified_identifier. Os extern_alias_directives, using_directives e type_declarations dessa file_scoped_namespace_declaration atuam como se fossem declarados na mesma ordem dentro do namespace_body dessa namespace_declaration.

Um arquivo de origem não pode conter tanto um file_scoped_namespace_declaration quanto um namespace_declaration. Um arquivo de origem não pode conter várias file_scoped_namespace_declarations. Uma compilation_unit não pode conter uma file_scoped_namespace_declaration e nem quaisquer instruções de nível superior type_declarations não podem preceder uma file_scoped_namespace_declaration.

Aliases externos

... inalterado ...