Compartilhar via


Diretiva global de uso

Nota

Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ele 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 discrepâ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/3428

A sintaxe de uma diretiva using é estendida com uma palavra-chave global opcional que pode preceder a palavra-chave 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 ';'
    ;
  • As global_using_directives são permitidas somente no nível de Unidade de Compilação (elas não podem ser usadas em uma namespace_declaration).
  • As global_using_directives, se houver, devem preceder quaisquer using_directives.
  • O escopo de uma global_using_directives se estende pelas namespace_member_declarations de todas as unidades de compilação no programa. O escopo de uma global_using_directive não inclui especificamente outras global_using_directives. Assim, os pares de global_using_directives ou de uma unidade de compilação diferente não interferem uns nos outros, e a ordem em que são escritos é irrelevante. O escopo de uma global_using_directive especificamente não inclui using_directives contidas em qualquer unidade de compilação do programa.

O efeito de adicionar uma global_using_directive a um programa pode ser considerado como o efeito de adicionar uma using_directive semelhante que é resolvida para o mesmo namespace ou tipo de destino para cada unidade de compilação do programa. No entanto, o destino de uma global_using_directive é resolvido no contexto da unidade de compilação que a contém.

§7.7 Escopos

Estes são os pontos relevantes com as adições propostas (que estão em negrito):

  • O escopo do nome definido por uma extern_alias_directive se estende pelas global_using_directives,using_directives, global_attributes e namespace_member_declarations da unidade de compilação ou do corpo de namespace que os contém. Uma extern_alias_directive não adiciona novos membros ao espaço de declaração subjacente. Em outras palavras, uma extern_alias_directive não é transitiva, mas afeta apenas a unidade de compilação ou o corpo do namespace no qual ela ocorre.
  • O escopo de um nome definido ou importado por uma global_using_directive se estende pelos global_attributes e namespace_member_declarations de todas as compilation_units do programa.

§7.8 Nomes de namespace e tipo

As alterações no algoritmo que determina o significado de um namespace_or_type_name são feitas como segue.

Este é o ponto relevante com as adições propostas (que estão em negrito):

  • Se o namespace_or_type_name tiver o formato I ou I<A1, ..., Ak>:
    • Se K for zero e a namespace_or_type_name aparecer dentro de uma declaração de método genérico (§15.6) e se essa declaração incluir um parâmetro de tipo (§15.2.3) com o nome I, o namespace_or_type_name se referirá a esse parâmetro de tipo.
    • Do contrário, se o namespace_or_type_name aparecer em uma declaração de tipo, para cada tipo de instância T (§15.3.2), começando com o tipo de instância dessa declaração de tipo e continuando com o tipo de instância de cada declaração de classe ou struct delimitadora (se houver):
      • Se K for zero e a declaração de T incluir um parâmetro de tipo com o nome I, o namespace_or_type_name se referirá a esse parâmetro de tipo.
      • Caso contrário, se o namespace_or_type_name aparecer dentro do corpo da declaração de tipo, e T ou qualquer um de seus tipos base contiver um tipo acessível aninhado, possuindo o nome I e parâmetros de tipo K, então o namespace_or_type_name se referirá a esse tipo construído com os argumentos de tipo fornecidos. Se houver mais de um tipo desse tipo, o tipo declarado dentro do tipo mais derivado será selecionado. Observe que membros não tipo (constantes, campos, métodos, propriedades, indexadores, operadores, construtores de instância, destruidores e construtores estáticos) e membros de tipo com um número diferente de parâmetros de tipo são ignorados ao determinar o significado do namespace_or_type_name.
    • Se as etapas anteriores não tiverem sido bem-sucedidas, para cada namespace N, começando com o namespace no qual o namespace_or_type_name ocorre, continuando com cada namespace delimitado (se houver) e terminando com o namespace global, as seguintes etapas serão avaliadas até que uma entidade esteja localizada:
      • Se K for zero e I for o nome de um namespace no N, então:
        • Se o local em que o namespace_or_type_name ocorre estiver dentro de uma declaração de namespace para N e a declaração de namespace contiver uma extern_alias_directive ou uma using_alias_directive que associe o nome I a um namespace ou tipo, ou se qualquer declaração de namespace para N no programa contiver uma global_using_alias_directive que associe o nome I a um namespace ou tipo, o namespace_or_type_name será ambíguo e ocorrerá um erro de tempo de compilação.
        • Caso contrário, o namespace_or_type_name refere-se ao namespace chamado I em N.
      • Caso contrário, se N contiver um tipo acessível com o nome I e parâmetros de tipo K, em seguida:
        • Se K for zero e o local em que o namespace_or_type_name ocorre estiver dentro de uma declaração de namespace para N e a declaração de namespace contiver uma extern_alias_directive ou uma using_alias_directive que associe o nome I a um namespace ou tipo, ou se qualquer declaração de namespace para N no programa contiver uma global_using_alias_directive que associe o nome I a um namespace ou tipo, o namespace_or_type_name será ambíguo e ocorrerá um erro de tempo de compilação.
        • Caso contrário, o namespace_or_type_name refere-se ao tipo construído com os argumentos de tipo fornecidos.
      • Do contrário, se o local em que o namespace_or_type_name ocorre estiver dentro de uma declaração de namespace para N:
        • Se K for zero e a declaração de namespace contiver uma extern_alias_directive ou uma using_alias_directive que associe o nome I a um namespace ou tipo importado, ou se qualquer declaração de namespace para N no programa contiver uma global_using_alias_directive que associe o nome I a um namespace ou tipo importado, o namespace_or_type_name fará referência a esse namespace ou tipo.
        • Do contrário, se os namespaces e as declarações de tipo importados pelas using_namespace_directives e using_alias_directives da declaração de namespace e os namespaces e as declarações de tipo importados pelas global_using_namespace_directives e global_using_static_directives de qualquer declaração de namespace para N no programa contiverem exatamente um tipo acessível com o nome I e parâmetros de tipo K, o namespace_or_type_name fará referência a esse tipo construído com os argumentos de tipo fornecidos.
        • Do contrário, se os namespaces e as declarações de tipo importados pelas using_namespace_directives e using_alias_directives da declaração de namespace e os namespaces e as declarações de tipo importados pelas global_using_namespace_directives e global_using_static_directives de qualquer declaração de namespace para N no programa contiverem mais de um tipo acessível com o nome I e parâmetros de tipo K, o namespace_or_type_name será ambíguo e ocorrerá um erro.
    • Caso contrário, o namespace_or_type_name será indefinido e ocorrerá um erro de tempo de compilação.

Nomes simples §12.8.4

As regras de avaliação do simple_name são alteradas da seguinte maneira.

Este é o ponto relevante com as adições propostas (que estão em negrito):

  • Caso contrário, para cada namespace N, começando com o namespace no qual o nome_simples ocorre, continuando com cada namespace envolvente (se houver) e terminando com o namespace global, as seguintes etapas são avaliadas até que uma entidade seja encontrada:
    • Se K for zero e I for o nome de um namespace no N, então:
      • Se o local em que o simple_name ocorre estiver dentro de uma declaração de namespace para N e a declaração de namespace contiver uma extern_alias_directive ou uma using_alias_directive que associe o nome I a um namespace ou tipo, ou se qualquer declaração de namespace para N no programa contiver uma global_using_alias_directive que associe o nome I a um namespace ou tipo, o simple_name será ambíguo e ocorrerá um erro de tempo de compilação.
      • Caso contrário, o simple_name refere-se ao namespace chamado I em N.
    • Caso contrário, se N contiver um tipo acessível com o nome I e parâmetros de tipo K, em seguida:
      • Se K for zero e o local em que o simple_name ocorre estiver dentro de uma declaração de namespace para N e a declaração de namespace contiver uma extern_alias_directive ou uma using_alias_directive que associe o nome I a um namespace ou tipo, ou se qualquer declaração de namespace para N no programa contiver uma global_using_alias_directive que associe o nome I a um namespace ou tipo, o simple_name será ambíguo e ocorrerá um erro de tempo de compilação.
      • Caso contrário, o namespace_or_type_name refere-se ao tipo construído com os argumentos de tipo fornecidos.
    • Caso contrário, se o local em que o simple_name ocorre estiver dentro de uma declaração de namespace para N:
      • Se K é zero e a declaração de namespace contém um extern_alias_directive ou using_alias_directive que associe o nome I a um namespace ou tipo importado, ou qualquer declaração de namespace para N no programa contém um global_using_alias_directive que associa o nome I a um namespace ou tipo importado, então o SimpleName refere-se a esse namespace ou tipo.
      • Do contrário, se os namespaces e as declarações de tipo importados pelas using_namespace_directives e using_static_directives da declaração de namespace e os namespaces e as declarações de tipo importados pelas global_using_namespace_directives e global_using_static_directives de qualquer declaração de namespace para N no programa contiverem exatamente um tipo acessível ou membro estático sem extensão com o nome I e parâmetros de tipo K, o simple_name fará referência a esse tipo ou membro construído com os argumentos de tipo fornecidos.
      • Do contrário, se os namespaces e tipos importados pelas using_namespace_directives da declaração de namespace e os namespaces e as declarações de tipo importados pelas global_using_namespace_directives e global_using_static_directives de qualquer declaração de namespace para N no programa contiverem mais de um tipo acessível ou membro estático sem extensão com o nome I e parâmetros de tipo K, o simple_name será ambíguo e ocorrerá um erro.

Invocações de métodos de extensão §12.8.10.3

As alterações são feitas no algoritmo para encontrar o melhor type_nameC da seguinte maneira. Este é o ponto relevante com as adições propostas (que estão em negrito):

  • Começando com a declaração de namespace delimitadora mais próxima, continuando com cada declaração de namespace delimitadora e terminando com a unidade de compilação continente, são feitas tentativas sucessivas de localizar um conjunto candidato de métodos de extensão:
    • Se o namespace ou a unidade de compilação fornecido contiver diretamente declarações de tipo não genérico Ci com métodos de extensão qualificados Mj, o conjunto desses métodos de extensão será o conjunto de candidatos.
    • Se os tipos Ci importados por using_static_declarations e declarados diretamente em namespaces importados por using_namespace_directives no namespace ou na unidade de compilação fornecidos e, se a unidade de compilação continente for atingida, importados por global_using_static_declarations e declarados diretamente em namespaces importados por global_using_namespace_directives no programa contêm diretamente os métodos de extensão qualificados Mj, o conjunto desses métodos de extensão é o conjunto candidato.

Unidades de compilação §14.2

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

compilation_unit
    : extern_alias_directive* global_using_directive* using_directive* global_attributes? namespace_member_declaration*
    ;

Um programa C# consiste em uma ou mais unidades de compilação, cada uma contida em um arquivo de origem separado. Quando um programa C# é compilado, todas as unidades de compilação são processadas juntas. Assim, as unidades de compilação podem depender umas das outras, possivelmente de forma circular.

As global_using_directives de uma unidade de compilação afetam os global_attributes e as namespace_member_declarations de todas as unidades de compilação do programa.

Aliases externos §14.4

O escopo de uma extern_alias_directive se estende pelas global_using_directives, using_directives, global_attributes e namespace_member_declarations da unidade de compilação ou do corpo de namespace que os contém.

Diretivas de alias using §14.5.2

A ordem em que as using_alias_directives são escritas não tem importância, e a resolução do namespace_or_type_name referenciado por uma using_alias_directive não é afetada pela using_alias_directive propriamente dita nem por outras using_directives contidas no corpo da unidade de compilação ou do namespace, e, se a using_alias_directive estiver contida em uma unidade de compilação, não será afetada pelas global_using_directives do programa. Em outras palavras, o namespace_or_type_name de uma using_alias_directive é resolvido como se a unidade de compilação ou o corpo do namespace que o contém não tivesse using_directives e, se a using_alias_directive estiver contida em uma unidade de compilação, o programa não tem global_using_directives. No entanto, uma using_alias_directive pode ser afetada por extern_alias_directives na unidade de compilação ou no corpo do namespace que a contém.

Diretivas de alias Global Using

Uma global_using_alias_directive introduz um identificador que funciona como alias para um namespace ou tipo no programa.

global_using_alias_directive
    : 'global' 'using' identifier '=' namespace_or_type_name ';'
    ;

Em declarações de membro em qualquer unidade de compilação de um programa que contém uma global_using_alias_directive, o identificador introduzido pela global_using_alias_directive pode ser usado para fazer referência ao namespace ou tipo fornecido.

O identificador de uma global_using_alias_directive deve ser exclusivo no espaço da declaração de qualquer unidade de compilação de um programa que contém a global_using_alias_directive.

Assim como os membros regulares, os nomes introduzidos por global_using_alias_directives são ocultos por membros com nomes semelhantes em escopos aninhados.

A ordem em que as global_using_alias_directives são escritas não tem importância, e a resolução do namespace_or_type_name referenciado por uma global_using_alias_directive não é afetada pela global_using_alias_directive propriamente dita ou por outras global_using_directives ou using_directives do programa. Em outras palavras, o namespace_or_type_name de uma global_using_alias_directive é resolvido como se a unidade de compilação que a contém não tivesse using_directives e todo o programa contido não tivesse global_using_directives. No entanto, uma global_using_alias_directive pode ser afetada por extern_alias_directives na unidade de compilação que a contém.

Uma global_using_alias_directive pode criar um alias para qualquer namespace ou tipo.

Acessar um namespace ou tipo através de um alias produz exatamente o mesmo resultado que acessar esse namespace ou tipo através de seu nome declarado.

Usar aliases pode nomear um tipo construído selado, mas não pode nomear uma declaração de tipo genérico não vinculado sem especificar argumentos de tipo.

Diretivas de Uso Global de Namespace

Uma global_using_namespace_directive importa os tipos contidos em um namespace para o programa, permitindo que o identificador de cada tipo seja usado sem qualificação.

global_using_namespace_directive
    : 'global' 'using' namespace_name ';'
    ;

Nas declarações de membro de um programa que contém uma global_using_namespace_directive, os tipos contidos no namespace fornecido podem ser referenciados diretamente.

Uma global_using_namespace_directive importa os tipos contidos no namespace fornecido, mas especificamente não importa namespaces aninhados.

Ao contrário de um global_using_alias_directive, um global_using_namespace_directive pode importar tipos cujos identificadores já estão definidos em uma unidade de compilação do programa. Na verdade, em uma determinada unidade de compilação, os nomes importados por qualquer global_using_namespace_directive do programa são ocultos por membros com nomes semelhantes na unidade de compilação.

Quando mais de um namespace ou tipo importado por global_using_namespace_directives ou global_using_static_directives no mesmo programa contêm tipos com o mesmo nome, as referências a esse nome como um type_name são consideradas ambíguas.

Além disso, quando mais de um namespace ou tipo importado por global_using_namespace_directives ou global_using_static_directives no mesmo programa contêm tipos ou membros com o mesmo nome, as referências a esse nome como simple_name são consideradas ambíguas.

O namespace_name referenciado por uma global_using_namespace_directive é resolvido da mesma forma que o namespace_or_type_name referenciado por uma global_using_alias_directive. Portanto, as global_using_namespace_directives no mesmo programa não afetam umas às outras e podem ser escritas em qualquer ordem.

Diretivas estáticas Global Using

Uma global_using_static_directive importa os tipos aninhados e os membros estáticos contidos diretamente em uma declaração de tipo para o programa que a contém, permitindo que o identificador de cada membro e tipo seja usado sem qualificação.

global_using_static_directive
    : 'global' 'using' 'static' type_name ';'
    ;

Nas declarações de membro em um programa que contém uma global_using_static_directive, os tipos aninhados acessíveis e os membros estáticos (exceto métodos de extensão) contidos diretamente na declaração do tipo especificado podem ser referenciados diretamente.

Uma global_using_static_directive especificamente não importa métodos de extensão diretamente como métodos estáticos, mas os disponibiliza para invocação de método de extensão.

Uma global_using_static_directive importa apenas membros e tipos declarados diretamente no tipo fornecido, não membros e tipos declarados em classes base.

As ambiguidades entre várias global_using_namespace_directives e global_using_static_directives são discutidas na seção sobre global_using_namespace_directives (acima).

Membro de alias qualificado §14.8

Foram feitas alterações no algoritmo que determina o significado de um qualified_alias_member, conforme a seguir.

Este é o ponto relevante com as adições propostas (que estão em negrito):

  • Caso contrário, começando com a declaração de namespace (§14.3) que imediatamente contém o qualified_alias_member (se houver), continuando com cada declaração de namespace circundante (se houver) e terminando com a unidade de compilação que contém o qualified_alias_member, as seguintes etapas são avaliadas até que uma entidade seja localizada:

    • Se a declaração de namespace ou a unidade de compilação contiver uma using_alias_directive que associe N a um tipo, ou, quando uma unidade de compilação é atingida, o programa contém uma global_using_alias_directive que associa N a um tipo, o qualified_alias_member será indefinido e ocorrerá um erro de tempo de compilação.
    • Do contrário, se a declaração de namespace ou a unidade de compilação contiver uma extern_alias_directive ou uma using_alias_directive que associe N a um namespace, *ou quando uma unidade de compilação é atingida, o programa contém uma global_using_alias_directive que associa N a um namespace, então:
      • Se o namespace associado a N contiver um namespace chamado I e K for zero, o qualified_alias_member fará referência a esse namespace.
      • Do contrário, se o namespace associado a N contiver um tipo não genérico chamado I e K for zero, o qualified_alias_member fará referência a esse tipo.
      • Caso contrário, se o namespace associado ao N contiver um tipo chamado I que tenha parâmetros de tipo K, o qualified_alias_member se referirá a esse tipo construído com os argumentos de tipo fornecidos.
      • Caso contrário, o qualified_alias_member fica indefinido e ocorrerá um erro de compilação.