Partilhar via


Namespaces com âmbito de ficheiro

Observação

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

Pode haver algumas discrepâncias entre a especificação do recurso e a implementação concluída. Essas diferenças são documentadas nas notas pertinentes da Language Design Meeting (LDM).

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

Questão campeã: https://github.com/dotnet/csharplang/issues/137

Resumo

Os namespaces com escopo de arquivo usam um formato menos detalhado 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 usar o formato namespace X.Y.Z; é equivalente a escrever namespace X.Y.Z { ... }, em que o restante do ficheiro após o namespace delimitado pelo ficheiro 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% arquivos são todos de uma destas formas:

namespace X.Y.Z
{
    // usings

    // types
}

ou

// usings

namespace X.Y.Z
{
    // types
}

No entanto, ambas as formas forçam o utilizador a indentar a maior parte do seu código e adicionar uma boa quantidade de formalidades para o que é efetivamente um conceito muito básico. Isso afeta a clareza, usa espaço horizontal e vertical, e muitas vezes é insatisfatório para usuários acostumados a C# e provenientes de outras linguagens (que geralmente têm menos cerimônia aqui).

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

Projeto detalhado

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

Comparação

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 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 seguido por zero ou mais global_attributes seguido por um compilation_unit_body. Um compilation_unit_body pode ser uma file_scoped_namespace_declaration ou zero ou mais instruçãos 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 ...

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

Declarações de namespace

Um namespace_declaration consiste na palavra-chave namespace, seguida por um nome e corpo de namespace, opcionalmente seguido por um ponto-e-vírgula. Um file_scoped_namespace_declaration é composto pela 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 os nomes totalmente qualificados N1.N2.A e N1.N2.B. Como as duas declarações contribuem para o mesmo espaço de declaração, teria sido 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 escrita 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, um file_scoped_namespace_declaration é tratado da mesma forma que um 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 agem como se fossem declarados na mesma ordem dentro da namespace_body dessa namespace_declaration.

Um ficheiro de origem não pode conter tanto um file_scoped_namespace_declaration como um namespace_declaration. Um arquivo de origem não pode conter vários file_scoped_namespace_declarations. Um compilation_unit não pode conter uma file_scoped_namespace_declaration e qualquer instrução de nível superiors. type_declarations não pode preceder um file_scoped_namespace_declaration.

Pseudónimos externos

... inalterado ...