Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
14.1 Geral
Os programas C# são organizados usando namespaces. Os namespaces são usados como um sistema organizacional "interno" para um programa e como um sistema organizacional "externo" - uma maneira de apresentar elementos do programa que são expostos a outros programas.
O uso de diretivas (§14.5) é fornecido para facilitar o uso de namespaces.
14.2 Unidades de compilação
Um compilation_unit consiste em zero ou mais extern_alias_directives seguidos por zero ou mais using_directiveseguidos por zero ou um global_attributes seguidos por zero ou mais namespace_member_declarations. O compilation_unit define a estrutura geral da entrada.
compilation_unit
: extern_alias_directive* using_directive* global_attributes?
namespace_member_declaration*
;
Um programa C# consiste em uma ou mais unidades de compilação. 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 extern_alias_directivede uma unidade de compilação afetam as using_directives, global_attributes e namespace_member_declarationdessa unidade de compilação, mas não têm nenhum efeito em outras unidades de compilação.
Os using_directivede uma unidade de compilação afetam os global_attributes e namespace_member_declarationdessa unidade de compilação, mas não têm efeito em outras unidades de compilação.
O global_attributes (§23.3) de uma unidade de compilação permite a especificação de atributos para o assembly e o módulo de destino. Assemblies e módulos atuam como contêineres físicos para tipos. Um conjunto pode consistir em vários módulos fisicamente separados.
Os namespace_member_declarationde cada unidade de compilação de um programa contribuem com membros para um único espaço de declaração chamado namespace global.
Example:
// File A.cs: class A {} // File B.cs: class B {}As duas unidades de compilação contribuem para o namespace global único, neste caso, declarando duas classes com os nomes
Atotalmente qualificados eB. Como as duas unidades de compilação 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.fim de exemplo
14.3 Declarações de namespace
Um namespace_declaration consiste no namespace da palavra-chave, seguido por um nome de namespace e corpo, opcionalmente seguido por um ponto-e-vírgula.
namespace_declaration
: 'namespace' qualified_identifier namespace_body ';'?
;
qualified_identifier
: identifier ('.' identifier)*
;
namespace_body
: '{' extern_alias_directive* using_directive*
namespace_member_declaration* '}'
;
Uma namespace_declaration pode ocorrer como uma declaração de nível superior em um compilation_unit ou como uma declaração de membro em outra namespace_declaration. Quando um namespace_declaration ocorre como uma declaração de nível superior em um compilation_unit, o namespace se torna um membro do namespace global. Quando um namespace_declaration ocorre dentro de outro namespace_declaration, o namespace interno se torna um membro do namespace externo. Em ambos os casos, o nome de um namespace deve ser exclusivo dentro do namespace que o contém.
Os namespaces são implicitamente public e a declaração de um namespace não pode incluir nenhum modificador de acesso.
Em um namespace_body, os using_directiveopcionais importam os nomes de outros namespaces, tipos e membros, permitindo que eles sejam referenciados diretamente em vez de por meio de nomes qualificados. Os namespace_member_declarationopcionais contribuem com membros para o espaço de declaração do namespace. Observe que todos os using_directivedevem aparecer antes de qualquer declaração de membro.
O qualified_identifier de um namespace_declaration pode ser um único identificador ou uma sequência de identificadores separados por tokens ".". A última forma permite que um programa defina um namespace aninhado sem aninhar lexicalmente várias declarações de namespace.
Example:
namespace N1.N2 { class A {} class B {} }é semanticamente equivalente a
namespace N1 { namespace N2 { class A {} class B {} } }fim de exemplo
Os namespaces são abertos e duas declarações de namespace com o mesmo nome totalmente qualificado (§7.8.3) contribuem para o mesmo espaço de declaração (§7.3).
Exemplo: no código a seguir
namespace N1.N2 { class A {} } namespace N1.N2 { class B {} }As duas declarações de namespace acima contribuem para o mesmo espaço de declaração, neste caso, declarando duas classes com os nomes
N1.N2.Atotalmente qualificados eN1.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.fim de exemplo
14.4 Diretivas de alias externos
Um extern_alias_directive apresenta um identificador que serve como um alias para um namespace. A especificação do namespace com alias é externa ao código-fonte do programa e também se aplica a namespaces aninhados do namespace com alias.
extern_alias_directive
: 'extern' 'alias' identifier ';'
;
O escopo de uma extern_alias_directive estende-se sobre as using_directives, global_attributes e namespace_member_declarationde seus compilation_unit ou namespace_body imediatamente.
Em uma unidade de compilação ou no corpo do namespace que contém um extern_alias_directive, o identificador introduzido pelo extern_alias_directive pode ser usado para referenciar o namespace aliased. É um erro de tempo de compilação para o identificador ser a palavra global.
O alias introduzido por um extern_alias_directive é muito semelhante ao alias introduzido por um using_alias_directive. Consulte o §14.5.2 para obter uma discussão mais detalhada sobre extern_alias_directivee using_alias_directives.
alias é uma palavra-chave contextual (§6.4.4) e só tem um significado especial quando segue imediatamente a extern palavra-chave em um extern_alias_directive.
Ocorrerá um erro se um programa declarar um alias externo para o qual nenhuma definição externa é fornecida.
Exemplo: o programa a seguir declara e usa dois aliases extern e
X, cada um deles,Yrepresenta a raiz de uma hierarquia de namespace distinta:extern alias X; extern alias Y; class Test { X::N.A a; X::N.B b1; Y::N.B b2; Y::N.C c; }O programa declara a existência dos aliases
Xexternos eY, mas as definições reais dos aliases são externas ao programa. As classes com nomesN.Bidênticos agora podem ser referenciadas comoX.N.BeY.N.B, ou, usando o qualificadorX::N.Bde alias de namespace eY::N.B. fim de exemplo
14.5 Usando diretivas
14.5.1 Geral
Uma diretiva de uso facilita o uso de namespaces e tipos definidos em outros namespaces. O uso de diretivas afeta o processo de resolução de nomes de namespace_or_type_names (§7.8) e simple_names (§12.8.4), mas, ao contrário das declarações, using_directivenão contribuem com novos membros para os espaços de declaração subjacentes das unidades de compilação ou namespaces nos quais são usados.
using_directive
: using_alias_directive
| using_namespace_directive
| using_static_directive
;
Um using_alias_directive (§14.5.2) introduz um alias para um namespace ou tipo.
Um using_namespace_directive (§14.5.3) importa os membros do tipo de um namespace.
Um using_static_directive (§14.5.4) importa os tipos aninhados e membros estáticos de um tipo.
O escopo de um using_directive se estende pela namespace_member_declarations de sua unidade de compilação ou corpo do namespace que contém imediatamente. O escopo de um using_directive especificamente não inclui seus using_directivepares. Portanto, os using_directivepares não afetam uns aos outros e a ordem em que são escritas é insignificante. Por outro lado, o escopo de um extern_alias_directive inclui os using_directivedefinidos na mesma unidade de compilação ou no corpo do namespace.
14.5.2 Usando diretivas de alias
Um using_alias_directive apresenta um identificador que serve como um alias para um namespace ou tipo dentro da unidade de compilação ou do corpo do namespace imediatamente delimitador.
using_alias_directive
: 'using' identifier '=' namespace_or_type_name ';'
;
Dentro de atributos globais e declarações de membro em uma unidade de compilação ou no corpo do namespace que contém um using_alias_directive, o identificador introduzido pelo using_alias_directive pode ser usado para fazer referência ao namespace ou tipo fornecido.
Example:
namespace N1.N2 { class A {} } namespace N3 { using A = N1.N2.A; class B: A {} }Acima, dentro das declarações de membro no
N3namespace,Ahá um alias paraN1.N2.A, e, portanto, classN3.Bderiva de classN1.N2.A. O mesmo efeito pode ser obtido criando um aliasRparaN1.N2e, em seguida, referenciandoR.A:namespace N3 { using R = N1.N2; class B : R.A {} }fim de exemplo
No uso de diretivas, atributos globais e declarações de membro em uma unidade de compilação ou no corpo do namespace que contém um extern_alias_directive, o identificador introduzido pelo extern_alias_directive pode ser usado para referenciar o namespace associado.
Exemplo: Por exemplo:
namespace N1 { extern alias N2; class B : N2::A {} }Acima, dentro das declarações de membro no
N1namespace,N2há um alias para algum namespace cuja definição é externa ao código-fonte do programa. ClasseN1.Bderiva de classeN2.A. O mesmo efeito pode ser obtido criando um aliasAparaN2.Ae, em seguida, referenciandoA:namespace N1 { extern alias N2; using A = N2::A; class B : A {} }fim de exemplo
Um extern_alias_directive ou using_alias_directive disponibiliza um alias em uma unidade de compilação específica ou no corpo do namespace, mas não contribui com novos membros para o espaço de declaração subjacente. Em outras palavras, uma diretiva de alias não é transitiva, mas afeta apenas a unidade de compilação ou o corpo do namespace no qual ela ocorre.
Exemplo: no código a seguir
namespace N3 { extern alias R1; using R2 = N1.N2; } namespace N3 { class B : R1::A, R2.I {} // Error, R1 and R2 unknown }Os escopos das diretivas de alias que introduzem
R1eR2se estendem apenas a declarações de membro no corpo do namespace no qual elas estão contidas, portantoR1, eR2são desconhecidos na segunda declaração de namespace. No entanto, colocar as diretivas de alias na unidade de compilação que contém faz com que o alias fique disponível em ambas as declarações de namespace:extern alias R1; using R2 = N1.N2; namespace N3 { class B : R1::A, R2.I {} } namespace N3 { class C : R1::A, R2.I {} }fim de exemplo
Cada extern_alias_directive ou using_alias_directive em um compilation_unit ou namespace_body contribui com um nome para o espaço de declaração de alias (§7.3) do compilation_unit ou namespace_body imediatamente delimitado. O identificador da diretiva de alias deve ser exclusivo dentro do espaço de declaração de alias correspondente. O identificador de alias não precisa ser exclusivo dentro do espaço de declaração global ou do espaço de declaração do namespace correspondente.
Example:
extern alias X; extern alias Y; using X = N1.N2; // Error: alias X already exists class Y {} // OkO alias using named
Xcausa um erro, pois já existe um alias nomeadoXna mesma unidade de compilação. A classe nomeadaYnão entra em conflito com o alias externo nomeadoY, pois esses nomes são adicionados a espaços de declaração distintos. O primeiro é adicionado ao espaço de declaração global e o último é adicionado ao espaço de declaração de alias para esta unidade de compilação.Quando um nome de alias corresponde ao nome de um membro de um namespace, o uso de qualquer um deles deve ser devidamente qualificado:
namespace N1.N2 { class B {} } namespace N3 { class A {} class B : A {} } namespace N3 { using A = N1.N2; using B = N1.N2.B; class W : B {} // Error: B is ambiguous class X : A.B {} // Error: A is ambiguous class Y : A::B {} // Ok: uses N1.N2.B class Z : N3.B {} // Ok: uses N3.B }No segundo corpo do namespace para
N3, o uso não qualificado deBresulta em um erro, sinceN3contém um membro chamadoBe o corpo do namespace que também declara um alias com nameB; da mesma forma paraA. A classeN3.Bpode ser referenciada comoN3.Bouglobal::N3.B. O aliasApode ser usado em um membro qualificado-alias (§14.8), comoA::B. O aliasBé essencialmente inútil. Ele não pode ser usado em um qualified_alias_member , pois somente aliases de namespace podem ser usados em um qualified_alias_member e aliasesBde um tipo.fim de exemplo
Assim como os membros regulares, os nomes introduzidos por alias_directives são ocultos por membros nomeados da mesma forma em escopos aninhados.
Exemplo: no código a seguir
using R = N1.N2; namespace N3 { class R {} class B: R.A {} // Error, R has no member A }A referência a
R.Ana declaração deBcausa um erro de tempo de compilação porqueRse refere aN3.R, nãoN1.N2.fim de exemplo
A ordem na qual extern_alias_directivesão escritas não tem significado. Da mesma forma, a ordem na qual using_alias_directivesão escritas não tem significado, mas todos os using_alias_directives virão depois de todos os extern_alias_directivena mesma unidade de compilação ou no corpo do namespace. 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 outras using_directiveno corpo da unidade de compilação ou do namespace que contém imediatamente, mas pode ser afetada por extern_alias_directives no corpo da unidade de compilação ou do namespace que contém imediatamente. 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 contém imediatamente não tivesse using_directives, mas tivesse o conjunto correto de extern_alias_directives.
Exemplo: no código a seguir
namespace N1.N2 {} namespace N3 { extern alias X; using R1 = X::N; // OK using R2 = N1; // OK using R3 = N1.N2; // OK using R4 = R2.N2; // Error, R2 unknown }o último using_alias_directive resulta em um erro de tempo de compilação porque ele não é afetado pelo using_alias_directive anterior. A primeira using_alias_directive não resulta em um erro, pois o escopo do alias X extern inclui o using_alias_directive.
fim de exemplo
Um using_alias_directive pode criar um alias para qualquer namespace ou tipo, incluindo o namespace no qual ele aparece e qualquer namespace ou tipo aninhado dentro desse namespace.
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.
Exemplo: Dado
namespace N1.N2 { class A {} } namespace N3 { using R1 = N1; using R2 = N1.N2; class B { N1.N2.A a; // refers to N1.N2.A R1.N2.A b; // refers to N1.N2.A R2.A c; // refers to N1.N2.A } }Os nomes
N1.N2.A,R1.N2.A, eR2.Asão equivalentes e todos se referem à declaração de classe cujo nome totalmente qualificado éN1.N2.A.fim de exemplo
Embora cada parte de um tipo parcial (§15.2.7) seja declarada dentro do mesmo namespace, as partes normalmente são escritas em declarações de namespace diferentes. Assim, diferentes extern_alias_directivee using_directivepodem estar presentes para cada parte. Ao interpretar nomes simples (§12.8.4) em uma parte, somente as extern_alias_directivee using_directivedos corpos do namespace e da unidade de compilação que inclui essa parte são consideradas. Isso pode resultar no mesmo identificador com significados diferentes em partes diferentes.
Example:
namespace N { using List = System.Collections.ArrayList; partial class A { List x; // x has type System.Collections.ArrayList } } namespace N { using List = Widgets.LinkedList; partial class A { List y; // y has type Widgets.LinkedList } }fim de exemplo
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 associada sem fornecer argumentos de tipo.
Example:
namespace N1 { class A<T> { class B {} } } namespace N2 { using W = N1.A; // Error, cannot name unbound generic type using X = N1.A.B; // Error, cannot name unbound generic type using Y = N1.A<int>; // Ok, can name closed constructed type using Z<T> = N1.A<T>; // Error, using alias cannot have type parameters }fim de exemplo
14.5.3 Usando diretivas de namespace
Um using_namespace_directive importa os tipos contidos em um namespace para a unidade de compilação ou o corpo do namespace imediatamente delimitador, permitindo que o identificador de cada tipo seja usado sem qualificação.
using_namespace_directive
: 'using' namespace_name ';'
;
Dentro de declarações de membro em uma unidade de compilação ou no corpo do namespace que contém um using_namespace_directive, os tipos contidos no namespace fornecido podem ser referenciados diretamente.
Example:
namespace N1.N2 { class A {} } namespace N3 { using N1.N2; class B : A {} }Acima, nas declarações de membro no
N3namespace, os membros do tipo deN1.N2estão diretamente disponíveis e, portanto, classN3.Bderiva de classN1.N2.A.fim de exemplo
Um using_namespace_directive importa os tipos contidos no namespace fornecido, mas especificamente não importa namespaces aninhados.
Exemplo: no código a seguir
namespace N1.N2 { class A {} } namespace N3 { using N1; class B : N2.A {} // Error, N2 unknown }o using_namespace_directive importa os tipos contidos
N1, mas não os namespaces aninhados emN1. Assim, a referência naN2.Adeclaração de resulta em um erro deBtempo de compilação porque nenhum membro nomeadoN2está no escopo.fim de exemplo
Ao contrário de um using_alias_directive, um using_namespace_directive pode importar tipos cujos identificadores já estão definidos dentro da unidade de compilação ou do corpo do namespace. Na verdade, os nomes importados por um using_namespace_directive são ocultos por membros nomeados da mesma forma na unidade de compilação ou no corpo do namespace.
Example:
namespace N1.N2 { class A {} class B {} } namespace N3 { using N1.N2; class A {} }Aqui, dentro das declarações de membro no
N3namespace,Arefere-se aN3.Aem vez deN1.N2.A.fim de exemplo
Como os nomes podem ser ambíguos quando mais de um namespace importado introduz o mesmo nome de tipo, um using_alias_directive é útil para desambiguar a referência.
Exemplo: no código a seguir
namespace N1 { class A {} } namespace N2 { class A {} } namespace N3 { using N1; using N2; class B : A {} // Error, A is ambiguous }ambos
N1eN2contêm um membroAe, comoN3importa ambos, aAreferência éN3um erro em tempo de compilação. Nessa situação, o conflito pode ser resolvido por meio da qualificação de referências paraA, ou introduzindo um using_alias_directive que escolhe um determinadoA. Por exemplo:namespace N3 { using N1; using N2; using A = N1.A; class B : A {} // A means N1.A }fim de exemplo
Além disso, quando mais de um namespace ou tipo importado por using_namespace_directives ou using_static_directives na mesma unidade de compilação ou corpo do namespace contêm tipos ou membros com o mesmo nome, as referências a esse nome como simple_name são consideradas ambíguas.
Example:
namespace N1 { class A {} } class C { public static int A; } namespace N2 { using N1; using static C; class B { void M() { A a = new A(); // Ok, A is unambiguous as a type-name A.Equals(2); // Error, A is ambiguous as a simple-name } } }
N1contém um membroAde tipo eCcontém um campoAestático e, comoN2importa ambos, referenciarAcomo um simple_name é ambíguo e um erro de tempo de compilação.fim de exemplo
Como um using_alias_directive, um using_namespace_directive não contribui com novos membros para o espaço de declaração subjacente da unidade de compilação ou namespace, mas afeta apenas a unidade de compilação ou o corpo do namespace no qual ele aparece.
O namespace_name referenciado por um using_namespace_directive é resolvido da mesma forma que o namespace_or_type_name referenciado por um using_alias_directive. Portanto, using_namespace_directives na mesma unidade de compilação ou no corpo do namespace não afetam uns aos outros e podem ser gravados em qualquer ordem.
14.5.4 Usando diretivas estáticas
Um using_static_directive importa os tipos aninhados e os membros estáticos contidos diretamente em uma declaração de tipo para a unidade de compilação ou o corpo do namespace imediatamente delimitador, permitindo que o identificador de cada membro e tipo seja usado sem qualificação.
using_static_directive
: 'using' 'static' type_name ';'
;
Dentro de declarações de membro em uma unidade de compilação ou no corpo do namespace que contém um using_static_directive, os tipos aninhados acessíveis e os membros estáticos (exceto os métodos de extensão) contidos diretamente na declaração do tipo especificado podem ser referenciados diretamente.
Example:
namespace N1 { class A { public class B {} public static B M() => new B(); } } namespace N2 { using static N1.A; class C { void N() { B b = M(); } } }No código anterior, dentro das declarações de membro no
N2namespace, os membros estáticos e os tipos aninhados de estão diretamente disponíveis e, portanto, o métodoN1.Aé capaz deNfazer referência aosBmembros eMdeN1.A.fim de exemplo
Um 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 (§12.8.10.3).
Example:
namespace N1 { static class A { public static void M(this string s){} } } namespace N2 { using static N1.A; class B { void N() { M("A"); // Error, M unknown "B".M(); // Ok, M known as extension method N1.A.M("C"); // Ok, fully qualified } } }o using_static_directive importa o método
Mde extensão contido,N1.Amas apenas como um método de extensão. Assim, a primeira referência aMno corpo de resulta em um erro deB.Ntempo de compilação porque nenhum membro nomeadoMestá no escopo.fim de exemplo
Um using_static_directive importa apenas membros e tipos declarados diretamente no tipo fornecido, não membros e tipos declarados em classes base.
Example:
namespace N1 { class A { public static void M(string s){} } class B : A { public static void M2(string s){} } } namespace N2 { using static N1.B; class C { void N() { M2("B"); // OK, calls B.M2 M("C"); // Error. M unknown } } }o using_static_directive importa o método
M2contidoN1.B, mas não importa o métodoMcontido emN1.A. Assim, a referência aMno corpo de resulta em um erro deC.Ntempo de compilação porque nenhum membro nomeadoMestá no escopo. Os desenvolvedores devem adicionar uma segundausing staticdiretiva para especificar que os métodos tambémN1.Adevem ser importados.fim de exemplo
Ambiguidades entre vários using_namespace_directives e using_static_directives são discutidas em §14.5.3.
14.6 Declarações de membro do namespace
Um namespace_member_declaration é um namespace_declaration (§14.3) ou um type_declaration (§14.7).
namespace_member_declaration
: namespace_declaration
| type_declaration
;
Uma unidade de compilação ou um corpo de namespace pode conter namespace_member_declarations e essas declarações contribuem com novos membros para o espaço de declaração subjacente da unidade de compilação ou do corpo do namespace que contém.
14.7 Declarações de tipo
Um type_declaration é um class_declaration (§15.2), um struct_declaration (§16.2), um interface_declaration (§19.2), um enum_declaration (§20.2) ou um delegate_declaration (§21.2).
type_declaration
: class_declaration
| struct_declaration
| interface_declaration
| enum_declaration
| delegate_declaration
;
Um type_declaration pode ocorrer como uma declaração de nível superior em uma unidade de compilação ou como uma declaração de membro em um namespace, classe ou struct.
Quando uma declaração de tipo para um tipo T ocorre como uma declaração de nível superior em uma unidade de compilação, o nome totalmente qualificado (§7.8.3) da declaração de tipo é o mesmo que o nome não qualificado da declaração (§7.8.2). Quando uma declaração de tipo para um tipo T ocorre dentro de uma declaração de namespace, classe ou struct, o nome totalmente qualificado (§7.8.3) da declaração de tipo é S.N, onde S está o nome totalmente qualificado da declaração de namespace, classe ou struct que contém e N é o nome não qualificado da declaração.
Um tipo declarado em uma classe, interface ou struct é chamado de tipo aninhado (§15.3.9).
Os modificadores de acesso permitidos e o acesso padrão para uma declaração de tipo dependem do contexto no qual a declaração ocorre (§7.5.2):
- Os tipos declarados em unidades de compilação ou namespaces podem ter
publicouinternalacessar. O padrão éinternalacesso. - Os tipos declarados em classes podem ter
public,protected internal,protected,private protected,internal, ouprivateaccess. O padrão éprivateacesso. - Os tipos declarados em structs podem ter
public,internal, ouprivateaccess. O padrão éprivateacesso.
14.8 Membro pseudônimo qualificado
14.8.1 Geral
O de alias de namespace possibilita garantir que as pesquisas de nome de tipo não sejam afetadas pela introdução de novos tipos e membros. O qualificador de alias de namespace sempre aparece entre dois identificadores chamados de identificadores à esquerda e à direita. Ao contrário do qualificador regular . , o identificador à esquerda do qualificador é procurado :: apenas como um extern ou usando alias.
Um qualified_alias_member fornece acesso explícito ao namespace global e extern ou usando aliases que são potencialmente ocultos por outras entidades.
qualified_alias_member
: identifier '::' identifier type_argument_list?
;
Um qualified_alias_member pode ser usado como um namespace_or_type_name (§7.8) ou como o operando esquerdo em um member_access (§12.8.7).
Um qualified_alias_member consiste em dois identificadores, conhecidos como identificadores à esquerda e à direita, semperados pelo :: token e, opcionalmente, seguidos por um type_argument_list. Quando o identificador à esquerda é global, o namespace global é pesquisado para o identificador à direita. Para qualquer outro identificador esquerdo, esse identificador é pesquisado como um extern ou usando alias (§14.4 e §14.5.2). Um erro de tempo de compilação ocorrerá se não houver esse alias ou se o alias fizer referência a um tipo. Se o alias fizer referência a um namespace, esse namespace será pesquisado pelo identificador à direita.
Um qualified_alias_member tem uma das duas formas:
-
N::I<A₁, ..., Aₑ>, ondeNeIrepresentam identificadores e<A₁, ..., Aₑ>é uma lista de argumentos de tipo.e( é sempre pelo menos um.) -
N::I, ondeNeIrepresentam identificadores. (Neste caso,eé considerado zero.)
Usando essa notação, o significado de um qualified_alias_member é determinado da seguinte maneira:
- Se
Nfor o identificadorglobal, o namespace global será pesquisadoI:- Se o namespace global contiver um namespace nomeado
Ieefor zero, o qualified_alias_member se referirá a esse namespace. - Caso contrário, se o namespace global contiver um tipo não genérico nomeado
Ieefor zero, o qualified_alias_member se referirá a esse tipo. - Caso contrário, se o namespace global contiver um tipo chamado
Ique tenhaeparâmetros de tipo, 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.
- Se o namespace global contiver um namespace nomeado
- Caso contrário, começando com a declaração de namespace (§14.3) imediatamente contendo o qualified_alias_member (se houver), continuando com cada declaração de namespace delimitado (se houver) e terminando com a unidade de compilação que contém o qualified_alias_member, as seguintes etapas serão avaliadas até que uma entidade esteja localizada:
- Se a declaração de namespace ou a unidade de compilação contiver um using_alias_directive que associe N a um tipo, o qualified_alias_member será indefinido e ocorrerá um erro de tempo de compilação.
- Caso contrário, se a declaração de namespace ou a unidade de compilação contiver um extern_alias_directive ou using_alias_directive associado a
Num namespace, então:- Se o namespace associado a
Ncontiver um namespace chamadoIeefor zero, o qualified_alias_member fará referência a esse namespace. - Do contrário, se o namespace associado a
Ncontiver um tipo não genérico chamadoIeefor zero, o qualified_alias_member fará referência a esse tipo. - Caso contrário, se o namespace associado ao
Ncontiver um tipo chamadoIque tenha parâmetros de tipoe, 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.
- Se o namespace associado a
- Caso contrário, o qualified_alias_member fica indefinido e ocorrerá um erro de compilação.
Exemplo: no código:
using S = System.Net.Sockets; class A { public static int x; } class C { public void F(int A, object S) { // Use global::A.x instead of A.x global::A.x += A; // Use S::Socket instead of S.Socket S::Socket s = S as S::Socket; } }A classe
Aé referenciada comglobal::Ae o tipoSystem.Net.Sockets.Socketé referenciado comS::Socket. UsarA.xeS.Socket, em vez disso, teria causado erros em tempo de compilação porqueAeSteria resolvido para os parâmetros.fim de exemplo
Observação: o identificador
globaltem um significado especial somente quando usado como o identificador esquerdo de uma qualified_alias_name. Não é uma palavra-chave e não é em si um alias; é uma palavra-chave contextual (§6.4.4). No código:class A { } class C { global.A x; // Error: global is not defined global::A y; // Valid: References A in the global namespace }using
global.Acausa um erro de tempo de compilação, pois não há nenhuma entidade nomeadaglobalno escopo. Se alguma entidade chamada global estivesse no escopo, entãoglobalelaglobal.Ateria resolvido para essa entidade.Usar
globalcomo o identificador esquerdo de um qualified_alias_member sempre causa uma pesquisa noglobalnamespace, mesmo que haja um alias usando o nomeglobal. No código:using global = MyGlobalTypes; class A { } class C { global.A x; // Valid: References MyGlobalTypes.A global::A y; // Valid: References A in the global namespace }
global.Aresolve eMyGlobalTypes.Aglobal::Aresolve para a classeAno namespace global.nota final
14.8.2 Unicidade de aliases
Cada unidade de compilação e corpo de namespace tem um espaço de declaração separado para aliases externos e aliases de uso. Assim, embora o nome de um alias externo ou alias using deva ser exclusivo dentro do conjunto de aliases externos e usando aliases declarados na unidade de compilação ou no corpo do namespace que contém imediatamente, um alias pode ter o mesmo nome que um tipo ou namespace, desde que seja usado apenas com o :: qualificador.
Exemplo: No seguinte:
namespace N { public class A {} public class B {} } namespace N { using A = System.IO; class X { A.Stream s1; // Error, A is ambiguous A::Stream s2; // Ok } }O nome
Atem dois significados possíveis no segundo corpo do namespace porque a classeAe o aliasAusing estão no escopo. Por esse motivo, o uso deAno nomeA.Streamqualificado é ambíguo e causa um erro em tempo de compilação. No entanto, o uso de com o qualificador não é um erro porqueAé pesquisado::Aapenas como um alias de namespace.fim de exemplo
ECMA C# draft specification