Diretiva de Utilização Global
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 capturadas 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/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 ';'
;
- Os global_using_directives são permitidos apenas no nível da Unidade de Compilação (não podem ser usados dentro de um namespace_declaration).
- Os global_using_directives, se houver, devem preceder quaisquer using_directives.
- O escopo de um global_using_directives se estende pelos namespace_member_declarations de todas as unidades de compilação dentro do programa. O âmbito de aplicação de um global_using_directive especificamente não inclui outros global_using_directives. Assim, os pares global_using_directives ou aqueles de uma unidade de compilação diferente não afetam uns aos outros, e a ordem em que são escritos é insignificante. O escopo de um global_using_directive especificamente não inclui using_directives imediatamente contidas em qualquer unidade de compilação do programa.
O efeito de adicionar um global_using_directive a um programa pode ser pensado como o efeito de adicionar um using_directive semelhante que se refere ao mesmo namespace ou tipo de destino em cada unidade de compilação do programa. No entanto, o destino de um global_using_directive é resolvido no contexto da unidade de compilação que o contém.
§7.7 Âmbitos
Estes são os pontos relevantes com os aditamentos propostos (que são em negrito):
- O escopo do nome definido por um extern_alias_directive se estende sobre os global_using_directives,using_directives, global_attributes e namespace_member_declarations da unidade de compilação ou do corpo de namespace que o contém imediatamente. Um extern_alias_directive não contribui com novos membros para o espaço de declaração subjacente. Em outras palavras, um extern_alias_directive não é transitivo, mas, em vez disso, afeta apenas a unidade de compilação ou o corpo do namespace no qual ele ocorre.
- O escopo de um nome definido ou importado por um global_using_directive se estende ao longo dos global_attributes e namespace_member_declarations de todos os compilation_units no programa.
§7.8 Nomes de namespace e tipo
As alterações são feitas no algoritmo que determina o significado de um namespace_or_type_name da seguinte forma.
Este é o ponto relevante com os aditamentos propostos (que são em negrito):
- Se o namespace_or_type_name estiver no formato
I
ou no formatoI<A1, ..., Ak>
:- Se
K
for zero e o 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 nomeI
, então o namespace_or_type_name refere-se a esse parâmetro de tipo. - Caso contrário, se o namespace_or_type_name aparecer dentro de uma declaração de tipo, então, para cada tipo de instância
T
(§15.3.2), começando pelo tipo de instância dessa declaração de tipo e continuando com o tipo de instância de cada classe ou estrutura que a envolve (se houver):- Se
K
for zero e a declaração deT
incluir um parâmetro type com nomeI
, então o namespace_or_type_name refere-se a esse parâmetro type. - Caso contrário, se o namespace_or_type_name aparecer no corpo da declaração de tipo e
T
ou qualquer um dos seus tipos base contiver um tipo acessível aninhado denominadoI
com parâmetros de tipoK
, então o namespace_or_type_name refere-se a esse tipo construído com os argumentos de tipo dados. Se houver mais de um desses tipos, o tipo declarado dentro do tipo mais derivado será selecionado. Observe que os 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
- Se as etapas anteriores não tiverem sido bem-sucedidas, então, para cada namespace
N
, começando com o namespace no qual o namespace_or_type_name ocorre, continuando com cada namespace de inclusão (se houver) e terminando com o namespace global, as etapas a seguir serão avaliadas até que uma entidade seja localizada:- Se
K
for zero eI
for o nome de um namespace noN
, então:- Se o local onde o namespace_or_type_name ocorre estiver incluído por uma declaração de namespace para
N
e a declaração de namespace contiver um extern_alias_directive ou using_alias_directive que associe o nomeI
a um namespace ou tipo, ou qualquer declaração de namespace paraN
no programa conterá um global_using_alias_directive que associa o nomeI
a um namespace ou tipo, então o namespace_or_type_name é ambíguo e ocorre um erro em tempo de compilação. - Caso contrário, o namespace_or_type_name refere-se ao namespace chamado
I
emN
.
- Se o local onde o namespace_or_type_name ocorre estiver incluído por uma declaração de namespace para
- Caso contrário, se
N
contiver um tipo acessível com nomeI
e parâmetros do tipoK
, então:- Se
K
for zero e o local onde o namespace_or_type_name ocorre for incluído por uma declaração de namespace paraN
e a declaração de namespace contiver uma extern_alias_directive ou using_alias_directive que associe o nomeI
a um namespace ou tipo, ou qualquer declaração de namespace paraN
no programa conterá um global_using_alias_directive que associa o nomeI
com um namespace ou tipo, então o namespace_or_type_name é ambíguo e ocorre um erro em tempo de compilação. - Caso contrário, o namespace_or_type_name refere-se ao tipo construído com os argumentos de tipo fornecidos.
- Se
- Caso contrário, se o local onde o namespace_or_type_name ocorre estiver incluído por uma declaração de namespace para
N
:- Se
K
for zero e a declaração de namespace contiver um extern_alias_directive ou using_alias_directive que associe o nomeI
a um namespace ou tipo importado, ou qualquer declaração de namespace paraN
no programa conterá um global_using_alias_directive que associa o nomeI
a um namespace ou tipo importado, então o namespace_or_type_name refere-se a esse namespace ou tipo. - Caso contrário, se os namespaces e declarações de tipo importados pelos using_namespace_directives e using_alias_directives da declaração de namespace e os namespaces e declarações de tipo importados pelos 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 que tenha o nomeI
eK
parâmetros de tipo, então o namespace_or_type_name refere-se àquele tipo construído com os argumentos de tipo fornecidos. - Caso contrário, se os namespaces e declarações de tipo importados pelos using_namespace_directives e using_alias_directives da declaração de namespace e os namespaces e declarações de tipo importados pelos 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 comI
eK
como parâmetros de tipo, isso torna o namespace_or_type_name ambíguo, causando um erro.
- Se
- Se
- Caso contrário, o namespace_or_type_name é indefinido e ocorre um erro em tempo de compilação.
- Se
Nomes simples §12.8.4
As alterações às regras de avaliação simple_name são feitas da seguinte forma.
Este é o ponto relevante com os aditamentos propostos (que são em negrito):
- Caso contrário, para cada namespace
N
, começando com o namespace no qual o simple_name ocorre, continuando com cada namespace de inclusão (se houver) e terminando com o namespace global, as etapas a seguir são avaliadas até que uma entidade seja localizada:- Se
K
for zero eI
for o nome de um namespace noN
, então:- Se o local onde o simple_name ocorre estiver incluído por uma declaração de namespace para
N
e a declaração de namespace contiver um extern_alias_directive ou using_alias_directive que associe o nomeI
a um namespace ou tipo, ou qualquer declaração de namespace paraN
no programa contém um global_using_alias_directive que associa o nomeI
a um namespace ou tipo, então o simple_name é ambíguo e ocorre um erro em tempo de compilação. - Caso contrário, o simple_name refere-se ao namespace chamado
I
emN
.
- Se o local onde o simple_name ocorre estiver incluído por uma declaração de namespace para
- Caso contrário, se
N
contiver um tipo acessível com o nomeI
e parâmetros de tipoK
, então:- Se
K
for zero e que o local onde o simple_name ocorre estiver envolvido por uma declaração de namespace paraN
e a declaração de namespace contiver uma extern_alias_directive ou using_alias_directive que associe o nomeI
a um namespace ou tipo, ou qualquer declaração de namespace paraN
no programa contém um global_using_alias_directive que associa o nomeI
a um namespace ou tipo, então o simple_name é ambíguo, o que resulta num erro em tempo de compilação. - Caso contrário, o namespace_or_type_name refere-se ao tipo construído com os argumentos de tipo fornecidos.
- Se
- Caso contrário, se o local onde o simple_name ocorre estiver delimitado por uma declaração de namespace para
N
:- Se
K
for zero e a declaração de namespace contiver um extern_alias_directive ou using_alias_directive que associe o nomeI
a um namespace ou tipo importado, ou qualquer declaração de namespace paraN
no programa conterá um global_using_alias_directive que associa o nomeI
a um namespace ou tipo importado, então o simple_name refere-se a esse namespace ou tipo. - Caso contrário, se os namespaces e declarações de tipos importadas pelos using_namespace_directives e using_static_directives da declaração de namespace e os namespaces e declarações de tipos importadas pelos 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 não de extensão com o nomeI
e comK
parâmetros de tipo, o simple_name refere-se a esse tipo ou membro, construído com os argumentos de tipo fornecidos. - Caso contrário, se os namespaces e tipos importados pelos using_namespace_directives da declaração de namespace e os namespaces e declarações de tipo importados pelos 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 que não seja de método de extensão com o nomeI
e parâmetros de tipoK
, então o simple_name é ambíguo e ocorre um erro.
- Se
- Se
Invocações de métodos de extensão §12.8.10.3
São feitas alterações no algoritmo para encontrar o melhor type_nameC
da seguinte forma.
Este é o ponto relevante com os aditamentos propostos (que são em negrito):
- Começando com a declaração de namespace de inclusão mais próxima, continuando com cada declaração de namespace anexada e terminando com a unidade de compilação que contém, são feitas tentativas sucessivas para encontrar um conjunto candidato de métodos de extensão:
- Se o namespace ou unidade de compilação fornecido contiver diretamente declarações de tipo não genéricas
Ci
com métodos de extensão elegíveisMj
, o conjunto desses métodos de extensão será o conjunto candidato. - Se os tipos
Ci
importados por using_static_declarations e declarados diretamente em namespaces importados por using_namespace_directiveno namespace ou unidade de compilação estiverem presentes, e, ao atingir a unidade de compilação correspondente, forem importados por global_using_static_declarations e declarados diretamente em namespaces importados por global_using_namespace_directiveno programa, contiverem diretamente métodos de extensão elegíveisMj
, então o conjunto desses métodos de extensão constitui o conjunto candidato.
- Se o namespace ou unidade de compilação fornecido contiver diretamente declarações de tipo não genéricas
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_directive's, seguido por zero ou mais using_directive's, seguido por zero ou mais global_attributes, seguido por zero ou mais namespace_member_declaration's.
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.
Os global_using_directives de uma unidade de compilação afetam os global_attributes e namespace_member_declarations de todas as unidades de compilação no programa.
Pseudónimos externos §14.4
O escopo de um extern_alias_directive estende-se sobre os global_using_directives,using_directives, global_attributes e namespace_member_declarations da sua unidade de compilação ou corpo de namespace que o contém imediatamente.
Usando diretivas de alias §14.5.2
A ordem em que using_alias_directives são escritos não tem significado e a resolução do namespace_or_type_name referenciado por um using_alias_directive não é afetada pelo próprio using_alias_directive ou por outros using_directives na unidade de compilação ou corpo de namespace imediatamente contendo e, se o using_alias_directive estiver imediatamente contido em uma unidade de compilação, não será afetado pelos global_using_directives no programa. Em outras palavras, o namespace_or_type_name de um using_alias_directive é resolvido como se a unidade de compilação ou o corpo do namespace que o contém imediatamente não tivessem using_directives e que, se o using_alias_directive estiver imediatamente contido numa unidade de compilação, o programa não tiver global_using_directives. No entanto, um using_alias_directive pode ser afetado por extern_alias_directives na unidade de compilação ou no corpo do namespace onde está imediatamente contido.
Usando diretivas de alias globalmente
Um global_using_alias_directive introduz um identificador que serve como alias para um namespace ou tipo dentro do programa.
global_using_alias_directive
: 'global' 'using' identifier '=' namespace_or_type_name ';'
;
Dentro das declarações de membro em qualquer unidade de compilação de um programa que contenha um global_using_alias_directive, o identificador introduzido pelo global_using_alias_directive pode ser usado para referenciar o namespace ou tipo especificado.
O identificador de uma diretiva_de_uso_global_alias deve ser exclusivo dentro do espaço de declaração de qualquer unidade de compilação de um programa que contenha a diretiva_de_uso_global_alias .
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 global_using_alias_directives são escritos não tem significado, e a resolução do namespace_or_type_name referenciado por um global_using_alias_directive não é afetada pelo próprio global_using_alias_directive ou por outros global_using_directiveou using_directives no programa. Em outras palavras, o namespace_or_type_name de um global_using_alias_directive é resolvido como se a unidade de compilação contígua não tivesse using_directives e todo o programa que a contém não tivesse global_using_directives. Um global_using_alias_directive pode, no entanto, ser afetado por extern_alias_directives na unidade de compilação que o contém imediatamente.
Um global_using_alias_directive pode criar um alias para qualquer namespace ou tipo.
Acessar um namespace ou tipo por meio de um alias produz exatamente o mesmo resultado que acessar esse namespace ou tipo por meio de seu nome declarado.
O uso de aliases pode nomear um tipo construído fechado, mas não pode nomear uma declaração de tipo genérico não vinculado sem fornecer argumentos de tipo.
Diretivas de namespace de uso global
Um 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 ';'
;
Dentro das declarações de membro num programa que contém uma diretiva global_using_namespace_directive, os tipos contidos no espaço de nomes fornecido podem ser referenciados diretamente.
Um 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 dentro de uma unidade de compilação do programa. Com efeito, em uma determinada unidade de compilação, nomes importados por qualquer global_using_namespace_directive no 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 um simple_name são consideradas ambíguas.
O namespace_name referenciado por um global_using_namespace_directive é resolvido da mesma forma que o namespace_or_type_name referenciado por um global_using_alias_directive. Assim, global_using_namespace_directives no mesmo programa não se afetam mutuamente e podem ser escritas em qualquer ordem.
Global Usando diretivas estáticas
Um global_using_static_directive importa os tipos aninhados e membros estáticos contidos diretamente em uma declaração de tipo no programa contido, permitindo que o identificador de cada membro e tipo seja usado sem especificação.
global_using_static_directive
: 'global' 'using' 'static' type_name ';'
;
Dentro de declarações de membro num programa que contém um global_using_static_directive, os tipos aninhados acessíveis e membros estáticos (exceto métodos de extensão) contidos diretamente na declaração do tipo dado podem ser referenciados diretamente.
Um global_using_static_directive, especificamente, não importa métodos de extensão diretamente como métodos estáticos, mas torna-os disponíveis para a invocação como métodos de extensão.
Um global_using_static_directive só importa membros e tipos declarados diretamente no tipo determinado, não membros e tipos declarados em classes base.
As ambiguidades entre múltiplos global_using_namespace_directives e global_using_static_directives são discutidas na seção para global_using_namespace_directives (acima).
Membro qualificado do alias §14.8
As alterações são feitas no algoritmo que determina o significado de um qualified_alias_member da seguinte forma.
Este é o ponto relevante com os aditamentos propostos (que são em negrito):
Caso contrário, começando com a declaração de namespace (§14.3) contendo imediatamente o qualified_alias_member (se houver), continuando com cada declaração de namespace anexando (se houver) e terminando com a unidade de compilação contendo o qualified_alias_member, as seguintes etapas são avaliadas até que uma entidade seja localizada:
- Se a declaração de namespace ou unidade de compilação contiver um using_alias_directive que associa
N
a um tipo, ou, quando uma unidade de compilação é atingida, o programa contém uma global_using_alias_directive que associaN
a um tipo, então o qualified_alias_member é indefinido e ocorre um erro em tempo de compilação. - Caso contrário, se a declaração de namespace ou unidade de compilação contiver um extern_alias_directive ou using_alias_directive que associa
N
a um namespace, *ou, quando uma unidade de compilação for atingida, o programa contiver um global_using_alias_directive que associaN
a um namespace, então:- Se o namespace associado a
N
contiver um namespace chamadoI
eK
for zero, o qualified_alias_member se refere a esse namespace. - Caso contrário, se o namespace associado a
N
contiver um tipo não genérico chamadoI
eK
for zero, o qualified_alias_member se refere a esse tipo. - Caso contrário, se o namespace associado a
N
contiver um tipo chamadoI
que tenhaK
parâmetros de tipo, o qualified_alias_member se refere a esse tipo construído com os argumentos de tipo fornecidos. - Caso contrário, o qualified_alias_member é indefinido e ocorre um erro em tempo de compilação.
- Se o namespace associado a
- Se a declaração de namespace ou unidade de compilação contiver um using_alias_directive que associa
C# feature specifications