14 Espacios de nombres
14.1 General
Los programas de C# se organizan mediante espacios de nombres. Los espacios de nombres se usan como un sistema de organización "interno" para un programa y como un sistema de organización "externo", una forma de presentar elementos de programa que se exponen a otros programas.
Se proporcionan directivas using (§14.5) para facilitar el uso de espacios de nombres.
14.2 Unidades de compilación
Un compilation_unit consta de cero o más extern_alias_directiveseguidos de cero o más using_directiveseguidos de cero o de un global_attributes seguido de cero o más namespace_member_declarations. El compilation_unit define la estructura general de la entrada.
compilation_unit
: extern_alias_directive* using_directive* global_attributes?
namespace_member_declaration*
;
Un programa de C# consta de una o varias unidades de compilación. Cuando se compila un programa de C#, todas las unidades de compilación se procesan juntas. Por lo tanto, las unidades de compilación pueden depender entre sí, posiblemente de forma circular.
Los extern_alias_directivede una unidad de compilación afectan a los using_directives, global_attributes y namespace_member_declarationde esa unidad de compilación, pero no tienen ningún efecto en otras unidades de compilación.
Los using_directivede una unidad de compilación afectan a los global_attributes y namespace_member_declarationde esa unidad de compilación, pero no tienen ningún efecto en otras unidades de compilación.
El global_attributes (§22.3) de una unidad de compilación permite la especificación de atributos para el ensamblado y el módulo de destino. Los ensamblados y módulos actúan como contenedores físicos para los tipos. Un ensamblado puede constar de varios módulos separados físicamente.
Los namespace_member_declarationde cada unidad de compilación de un programa contribuyen a los miembros a un único espacio de declaración denominado espacio de nombres global.
Ejemplo:
// File A.cs: class A {} // File B.cs: class B {}
Las dos unidades de compilación contribuyen al único espacio de nombres global, en este caso declarando dos clases con los nombres
A
completos yB
. Dado que las dos unidades de compilación contribuyen al mismo espacio de declaración, habría sido un error si cada una contenía una declaración de un miembro con el mismo nombre.ejemplo final
14.3 Declaraciones de espacio de nombres
Un namespace_declaration consta del espacio de nombres de palabra clave, seguido de un nombre de espacio de nombres y un cuerpo, seguido opcionalmente de un punto y coma.
namespace_declaration
: 'namespace' qualified_identifier namespace_body ';'?
;
qualified_identifier
: identifier ('.' identifier)*
;
namespace_body
: '{' extern_alias_directive* using_directive*
namespace_member_declaration* '}'
;
Un namespace_declaration puede producirse como una declaración de nivel superior en una compilation_unit o como una declaración de miembro dentro de otro namespace_declaration. Cuando un namespace_declaration se produce como una declaración de nivel superior en un compilation_unit, el espacio de nombres se convierte en miembro del espacio de nombres global. Cuando se produce un namespace_declaration dentro de otra namespace_declaration, el espacio de nombres interno se convierte en miembro del espacio de nombres externo. En cualquier caso, el nombre de un espacio de nombres será único dentro del espacio de nombres contenedor.
Los espacios de nombres son implícitamente public
y la declaración de un espacio de nombres no puede incluir ningún modificador de acceso.
Dentro de un namespace_body, los using_directiveopcionales importan los nombres de otros espacios de nombres, tipos y miembros, lo que les permite hacer referencia directamente en lugar de a través de nombres calificados. Los namespace_member_declarationopcionales contribuyen a los miembros del espacio de declaraciones del espacio de nombres. Tenga en cuenta que todas las using_directiveaparecerán antes de cualquier declaración miembro.
El qualified_identifier de un namespace_declaration puede ser un identificador único o una secuencia de identificadores separados por tokens ".
". Este último formulario permite a un programa definir un espacio de nombres anidado sin anidar léxicamente varias declaraciones de espacio de nombres.
Ejemplo:
namespace N1.N2 { class A {} class B {} }
es semánticamente equivalente a
namespace N1 { namespace N2 { class A {} class B {} } }
ejemplo final
Los espacios de nombres están abiertos y dos declaraciones de espacio de nombres con el mismo nombre completo (§7.8.2) contribuyen al mismo espacio de declaración (§7.3).
Ejemplo: en el código siguiente
namespace N1.N2 { class A {} } namespace N1.N2 { class B {} }
las dos declaraciones de espacio de nombres anteriores contribuyen al mismo espacio de declaración, en este caso declarando dos clases con los nombres
N1.N2.A
completos yN1.N2.B
. Dado que las dos declaraciones contribuyen al mismo espacio de declaración, habría sido un error si cada una contenía una declaración de un miembro con el mismo nombre.ejemplo final
14.4 Directivas de alias extern
Un extern_alias_directive introduce un identificador que actúa como alias para un espacio de nombres. La especificación del espacio de nombres con alias es externa al código fuente del programa y también se aplica a los espacios de nombres anidados del espacio de nombres con alias.
extern_alias_directive
: 'extern' 'alias' identifier ';'
;
El ámbito de un extern_alias_directive se extiende a través de los using_directive s, global_attributes y namespace_member_declarationde su compilation_unit o namespace_body inmediatamente.
Dentro de una unidad de compilación o un cuerpo del espacio de nombres que contiene un extern_alias_directive, el identificador introducido por el extern_alias_directive se puede usar para hacer referencia al espacio de nombres con alias. Es un error en tiempo de compilación para que el identificador sea la palabra global
.
El alias introducido por un extern_alias_directive es muy similar al alias introducido por un using_alias_directive. Consulte §14.5.2 para obtener una explicación más detallada de extern_alias_directives y using_alias_directives.
alias
es una palabra clave contextual (§6.4.4) y solo tiene un significado especial cuando sigue inmediatamente la extern
palabra clave en un extern_alias_directive.
Se produce un error si un programa declara un alias extern para el que no se proporciona ninguna definición externa.
Ejemplo: el siguiente programa declara y usa dos alias extern,
X
yY
, cada uno de los cuales representa la raíz de una jerarquía de espacios de nombres distinto:extern alias X; extern alias Y; class Test { X::N.A a; X::N.B b1; Y::N.B b2; Y::N.C c; }
El programa declara la existencia de los alias
X
de extern yY
, pero las definiciones reales de los alias son externas al programa. Ahora se puede hacer referencia a las clases conN.B
nombre idéntico comoX.N.B
yY.N.B
, o , mediante el calificadorX::N.B
de alias de espacio de nombres yY::N.B
. ejemplo final
14.5 Uso de directivas
14.5.1 General
Las directivas using facilitan el uso de espacios de nombres y tipos definidos en otros espacios de nombres. El uso de directivas afecta al proceso de resolución de nombres de namespace_or_type_name s (§7.8) y simple_names (§12.8.4), pero a diferencia de las declaraciones, using_directives no contribuyen nuevos miembros a los espacios de declaración subyacentes de las unidades de compilación o los espacios de nombres dentro de losque se usan.
using_directive
: using_alias_directive
| using_namespace_directive
| using_static_directive
;
Un using_alias_directive (§14.5.2) presenta un alias para un espacio de nombres o tipo.
Un using_namespace_directive (§14.5.3) importa los miembros de tipo de un espacio de nombres.
Un using_static_directive (§14.5.4) importa los tipos anidados y los miembros estáticos de un tipo.
El ámbito de un using_directive se extiende a través del namespace_member_declarations de su unidad de compilación o cuerpo del espacio de nombres inmediatamente. El ámbito de un using_directive específicamente no incluye sus using_directivedel mismo nivel. Por lo tanto, la using_directivedel mismo nivel no afecta entre sí y el orden en el que se escriben es insignificante. En cambio, el ámbito de un extern_alias_directive incluye los using_directivedefinidos en la misma unidad de compilación o cuerpo del espacio de nombres.
14.5.2 Uso de directivas de alias
Un using_alias_directive introduce un identificador que actúa como alias para un espacio de nombres o un tipo dentro de la unidad de compilación o el cuerpo del espacio de nombres incluido inmediatamente.
using_alias_directive
: 'using' identifier '=' namespace_or_type_name ';'
;
Dentro de atributos globales y declaraciones de miembro en una unidad de compilación o un cuerpo de espacio de nombres que contiene un using_alias_directive, el identificador introducido por el using_alias_directive se puede usar para hacer referencia al espacio de nombres o al tipo especificados.
Ejemplo:
namespace N1.N2 { class A {} } namespace N3 { using A = N1.N2.A; class B: A {} }
Anteriormente, dentro de las declaraciones de miembro del
N3
espacio de nombres ,A
es un alias paraN1.N2.A
y, por tanto, la claseN3.B
deriva de la claseN1.N2.A
. El mismo efecto se puede obtener creando un aliasR
paraN1.N2
y haciendo referencia aR.A
:namespace N3 { using R = N1.N2; class B : R.A {} }
ejemplo final
Dentro de las directivas using, los atributos globales y las declaraciones de miembro en un cuerpo de unidad de compilación o espacio de nombres que contiene un extern_alias_directive, el identificador introducido por el extern_alias_directive se puede usar para hacer referencia al espacio de nombres asociado.
Ejemplo: por ejemplo:
namespace N1 { extern alias N2; class B : N2::A {} }
Anteriormente, dentro de las declaraciones de miembro del
N1
espacio de nombres,N2
es un alias para algún espacio de nombres cuya definición es externa al código fuente del programa. La claseN1.B
deriva de la claseN2.A
. El mismo efecto se puede obtener creando un aliasA
paraN2.A
y haciendo referencia aA
:namespace N1 { extern alias N2; using A = N2::A; class B : A {} }
ejemplo final
Un extern_alias_directive o using_alias_directive hace que un alias esté disponible dentro de una unidad de compilación determinada o un cuerpo del espacio de nombres, pero no contribuye a ningún nuevo miembro al espacio de declaración subyacente. En otras palabras, una directiva de alias no es transitiva, sino que solo afecta al cuerpo de la unidad de compilación o del espacio de nombres en el que se produce.
Ejemplo: en el código siguiente
namespace N3 { extern alias R1; using R2 = N1.N2; } namespace N3 { class B : R1::A, R2.I {} // Error, R1 and R2 unknown }
los ámbitos de las directivas de alias que introducen
R1
yR2
solo se extienden a las declaraciones de miembro en el cuerpo del espacio de nombres en el que se encuentran, por lo queR1
yR2
se desconocen en la segunda declaración de espacio de nombres. Sin embargo, colocar las directivas de alias en la unidad de compilación contenedora hace que el alias esté disponible en ambas declaraciones de espacio de nombres:extern alias R1; using R2 = N1.N2; namespace N3 { class B : R1::A, R2.I {} } namespace N3 { class C : R1::A, R2.I {} }
ejemplo final
Cada extern_alias_directive o using_alias_directive en un compilation_unit o namespace_body contribuye a un nombre al espacio de declaración de alias (§7.3) de la compilation_unit o namespace_body inmediatamente envolventes. El identificador de la directiva de alias será único dentro del espacio de declaración de alias correspondiente. El identificador de alias no debe ser único dentro del espacio de declaración global o el espacio de declaración del espacio de nombres correspondiente.
Ejemplo:
extern alias X; extern alias Y; using X = N1.N2; // Error: alias X already exists class Y {} // Ok
El alias que usa el nombre
X
produce un error, ya que ya hay un alias denominadoX
en la misma unidad de compilación. La clase denominadaY
no entra en conflicto con el alias extern denominadoY
, ya que estos nombres se agregan a espacios de declaración distintos. El primero se agrega al espacio de declaración global y este último se agrega al espacio de declaración de alias para esta unidad de compilación.Cuando un nombre de alias coincide con el nombre de un miembro de un espacio de nombres, el uso de cualquiera de los dos se calificará adecuadamente:
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 }
En el segundo cuerpo del espacio de nombres para
N3
, el uso no completo deB
da como resultado un error, ya queN3
contiene un miembro denominadoB
y el cuerpo del espacio de nombres que también declara un alias con nombreB
; del mismo modo paraA
. Se puede hacer referencia a la claseN3.B
comoN3.B
oglobal::N3.B
. El aliasA
se puede usar en un miembro calificado de alias (§14.8), comoA::B
. El aliasB
es esencialmente inútil. No se puede usar en un qualified_alias_member , ya que solo se pueden usar alias de espacio de nombres en un qualified_alias_member yB
alias de un tipo.ejemplo final
Al igual que los miembros normales, los nombres introducidos por alias_directives están ocultos por miembros con nombre similar en ámbitos anidados.
Ejemplo: en el código siguiente
using R = N1.N2; namespace N3 { class R {} class B: R.A {} // Error, R has no member A }
la referencia a
R.A
en la declaración de produce un error en tiempo deB
compilación porqueR
hace referencia aN3.R
, noN1.N2
a .ejemplo final
El orden en que se escriben extern_alias_directive no tiene importancia. Del mismo modo, el orden en que se escriben using_alias_directives no tiene ningún significado, pero todos los using_alias_directives vendrán después de todos los extern_alias_directiveen la misma unidad de compilación o cuerpo del espacio de nombres. La resolución de la namespace_or_type_name a la que hace referencia un using_alias_directive no se ve afectada por el propio using_alias_directive ni por otros using_directiveen el cuerpo de la unidad de compilación o espacio de nombres inmediatamente que contiene, pero puede verse afectado por extern_alias_directiveen el cuerpo de espacio de nombres o unidad de compilación que contiene inmediatamente. Es decir, el namespace_or_type_name de un using_alias_directive se resuelve como si el cuerpo de la unidad de compilación o del espacio de nombres que contiene inmediatamente no tuviera using_directive s, pero tiene el conjunto correcto de extern_alias_directives.
Ejemplo: en el código siguiente
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 }
el último using_alias_directive produce un error en tiempo de compilación porque no se ve afectado por el using_alias_directive anterior. El primer using_alias_directive no produce un error, ya que el ámbito del alias X de extern incluye el using_alias_directive.
ejemplo final
Un using_alias_directive puede crear un alias para cualquier espacio de nombres o tipo, incluido el espacio de nombres en el que aparece y cualquier espacio de nombres o tipo anidado dentro de ese espacio de nombres.
El acceso a un espacio de nombres o un tipo a través de un alias produce exactamente el mismo resultado que el acceso a ese espacio de nombres o tipo a través de su nombre declarado.
Ejemplo: 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 } }
los nombres
N1.N2.A
,R1.N2.A
y son equivalentes yR2.A
todos hacen referencia a la declaración de clase cuyo nombre completo esN1.N2.A
.ejemplo final
Aunque cada parte de un tipo parcial (§15.2.7) se declara dentro del mismo espacio de nombres, las partes normalmente se escriben en diferentes declaraciones de espacio de nombres. Por lo tanto, se pueden presentar diferentes extern_alias_directives y using_directivepara cada parte. Al interpretar nombres simples (§12.8.4) dentro de una parte, solo se consideran los extern_alias_directives y using_directivede los cuerpos del espacio de nombres y la unidad de compilación que incluye esa parte. Esto puede dar lugar a que el mismo identificador tenga significados diferentes en partes diferentes.
Ejemplo:
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 } }
ejemplo final
El uso de alias puede asignar un nombre a un tipo construido cerrado, pero no puede asignar un nombre a una declaración de tipo genérico sin proporcionar argumentos de tipo.
Ejemplo:
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 }
ejemplo final
14.5.3 Uso de directivas de espacio de nombres
Un using_namespace_directive importa los tipos contenidos en un espacio de nombres en el cuerpo de espacio de nombres o unidad de compilación envolvente inmediatamente, lo que permite usar el identificador de cada tipo sin cualificación.
using_namespace_directive
: 'using' namespace_name ';'
;
Dentro de las declaraciones de miembro de una unidad de compilación o un cuerpo de espacio de nombres que contiene un using_namespace_directive, se puede hacer referencia directamente a los tipos contenidos en el espacio de nombres especificado.
Ejemplo:
namespace N1.N2 { class A {} } namespace N3 { using N1.N2; class B : A {} }
Anteriormente, dentro de las declaraciones de miembro del
N3
espacio de nombres, los miembros de tipo deN1.N2
están disponibles directamente y, por tanto, la claseN3.B
deriva de la claseN1.N2.A
.ejemplo final
Un using_namespace_directive importa los tipos contenidos en el espacio de nombres especificado, pero específicamente no importa espacios de nombres anidados.
Ejemplo: en el código siguiente
namespace N1.N2 { class A {} } namespace N3 { using N1; class B : N2.A {} // Error, N2 unknown }
el using_namespace_directive importa los tipos contenidos en
N1
, pero no los espacios de nombres anidados enN1
. Por lo tanto, la referencia aN2.A
en la declaración de da como resultado un error en tiempo deB
compilación porque ningún miembro denominadoN2
está en el ámbito.ejemplo final
A diferencia de un using_alias_directive, un using_namespace_directive puede importar tipos cuyos identificadores ya están definidos dentro de la unidad de compilación envolvente o el cuerpo del espacio de nombres. En efecto, los nombres importados por un using_namespace_directive están ocultos por miembros con nombre similar en la unidad de compilación envolvente o el cuerpo del espacio de nombres.
Ejemplo:
namespace N1.N2 { class A {} class B {} } namespace N3 { using N1.N2; class A {} }
Aquí, dentro de las declaraciones de miembro del
N3
espacio de nombres,A
hace referencia aN3.A
en lugar deN1.N2.A
a .ejemplo final
Dado que los nombres pueden ser ambiguos cuando más de un espacio de nombres importado introduce el mismo nombre de tipo, un using_alias_directive es útil para eliminar la ambigüedad de la referencia.
Ejemplo: en el código siguiente
namespace N1 { class A {} } namespace N2 { class A {} } namespace N3 { using N1; using N2; class B : A {} // Error, A is ambiguous }
N2
yN1
contienen un miembroA
, y porqueN3
importa ambos, hacer referenciaA
a en es un error enN3
tiempo de compilación. En esta situación, el conflicto se puede resolver a través de la calificación de referencias aA
o introduciendo un using_alias_directive que elige un determinadoA
. Por ejemplo:namespace N3 { using N1; using N2; using A = N1.A; class B : A {} // A means N1.A }
ejemplo final
Además, cuando más de un espacio de nombres o un tipo importados por using_namespace_directives o using_static_directives en la misma unidad de compilación o cuerpo del espacio de nombres contienen tipos o miembros por el mismo nombre, las referencias a ese nombre que una simple_name se consideran ambiguas.
Ejemplo:
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 } } }
N1
contiene un miembroA
de tipo yC
contiene un campoA
estático y, dado queN2
importa ambos, hacer referenciaA
a un simple_name es ambiguo y un error en tiempo de compilación.ejemplo final
Al igual que un using_alias_directive, un using_namespace_directive no contribuye a ningún nuevo miembro al espacio de declaración subyacente de la unidad de compilación o el espacio de nombres, sino que, en su lugar, afecta solo al cuerpo de la unidad de compilación o del espacio de nombres en el que aparece.
El namespace_name al que hace referencia un using_namespace_directive se resuelve de la misma manera que el namespace_or_type_name al que hace referencia un using_alias_directive. Por lo tanto, using_namespace_directives en la misma unidad de compilación o cuerpo del espacio de nombres no afectan entre sí y se pueden escribir en cualquier orden.
14.5.4 Uso de directivas estáticas
Un using_static_directive importa los tipos anidados y los miembros estáticos contenidos directamente en una declaración de tipo en el cuerpo de espacio de nombres o unidad de compilación envolvente inmediatamente, lo que permite usar el identificador de cada miembro y tipo sin cualificación.
using_static_directive
: 'using' 'static' type_name ';'
;
Dentro de las declaraciones de miembro de una unidad de compilación o un cuerpo de espacio de nombres que contiene un using_static_directive, se puede hacer referencia directamente a los tipos anidados y a los miembros estáticos accesibles (excepto los métodos de extensión) contenidos directamente en la declaración del tipo especificado.
Ejemplo:
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(); } } }
En el código anterior, dentro de las declaraciones de miembro del
N2
espacio de nombres, los miembros estáticos y los tipos anidados deN1.A
están disponibles directamente y, por tanto, el métodoN
puede hacer referencia a losB
miembros yM
deN1.A
.ejemplo final
Un using_static_directive específicamente no importa métodos de extensión directamente como métodos estáticos, pero hace que estén disponibles para la invocación del método de extensión (§12.8.9.3).
Ejemplo:
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 } } }
el using_static_directive importa el método
M
de extensión contenido enN1.A
, pero solo como un método de extensión. Por lo tanto, la primera referencia aM
en el cuerpo de da como resultado un error en tiempo deB.N
compilación porque ningún miembro denominadoM
está en el ámbito.ejemplo final
Un using_static_directive solo importa miembros y tipos declarados directamente en el tipo especificado, no miembros y tipos declarados en clases base.
Ejemplo:
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 } } }
el using_static_directive importa el método
M2
contenido enN1.B
, pero no importa el métodoM
contenido enN1.A
. Por lo tanto, la referencia aM
en el cuerpo de da como resultado un error en tiempo deC.N
compilación porque ningún miembro denominadoM
está en el ámbito. Los desarrolladores deben agregar una segundausing static
directiva para especificar que los métodos deN1.A
también deben importarse.ejemplo final
Las ambigüedades entre varios using_namespace_directives y using_static_directives se describen en §14.5.3.
14.6 Declaraciones de miembro de espacio de nombres
Un namespace_member_declaration es un namespace_declaration (§14.3) o un type_declaration (§14.7).
namespace_member_declaration
: namespace_declaration
| type_declaration
;
Una unidad de compilación o un cuerpo de espacio de nombres puede contener namespace_member_declarations, y estas declaraciones contribuyen a nuevos miembros al espacio de declaración subyacente de la unidad de compilación o el cuerpo del espacio de nombres.
14.7 Declaraciones de tipo
Un type_declaration es un class_declaration (§15.2), un struct_declaration (§16.2), un interface_declaration (§18.2), un enum_declaration (§19.2) o un delegate_declaration (§20.2).
type_declaration
: class_declaration
| struct_declaration
| interface_declaration
| enum_declaration
| delegate_declaration
;
Un type_declaration puede producirse como una declaración de nivel superior en una unidad de compilación o como una declaración de miembro dentro de un espacio de nombres, una clase o una estructura.
Cuando se produce una declaración de tipo para un tipo T
como una declaración de nivel superior en una unidad de compilación, el nombre completo (§7.8.2) de la declaración de tipo es el mismo que el nombre no completo de la declaración (§7.8.2). Cuando se produce una declaración de tipo para un tipo T
dentro de una declaración de espacio de nombres, clase o estructura, el nombre completo (§7.8.3) de la declaración S.N
de tipo , donde S
es el nombre completo del espacio de nombres contenedor, la clase o la declaración de estructura, y N
es el nombre no completo de la declaración.
Un tipo declarado dentro de una clase o estructura se denomina tipo anidado (§15.3.9).
Los modificadores de acceso permitidos y el acceso predeterminado para una declaración de tipo dependen del contexto en el que tiene lugar la declaración (§7.5.2):
- Los tipos declarados en unidades de compilación o espacios de nombres pueden tener
public
ointernal
tener acceso. El valor predeterminado esinternal
el acceso. - Los tipos declarados en clases pueden tener
public
acceso a ,protected internal
,protected
,private protected
, ,internal
oprivate
. El valor predeterminado esprivate
el acceso. - Los tipos declarados en estructuras pueden tener
public
acceso a ,internal
oprivate
. El valor predeterminado esprivate
el acceso.
14.8 Miembro de alias calificado
14.8.1 General
El calificador ::
de alias de espacio de nombres permite garantizar que las búsquedas de nombres de tipo no se ven afectadas por la introducción de nuevos tipos y miembros. El calificador de alias de espacio de nombres siempre aparece entre dos identificadores denominados identificadores izquierdo y derecho. A diferencia del calificador normal .
, el identificador izquierdo del ::
calificador solo se busca como un extern o mediante alias.
Un qualified_alias_member proporciona acceso explícito al espacio de nombres global y a extern o mediante alias que pueden ocultar otras entidades.
qualified_alias_member
: identifier '::' identifier type_argument_list?
;
Un qualified_alias_member se puede usar como namespace_or_type_name (§7.8) o como operando izquierdo en un member_access (§12.8.7).
Un qualified_alias_member consta de dos identificadores, denominados identificadores izquierdo y derecho, separados por el ::
token y, opcionalmente, seguidos de un type_argument_list. Cuando el identificador izquierdo es global, el espacio de nombres global se busca en el identificador derecho. Para cualquier otro identificador izquierdo, ese identificador se busca como un extern o mediante alias (§14.4 y §14.5.2). Se produce un error en tiempo de compilación si no hay ese alias o el alias hace referencia a un tipo. Si el alias hace referencia a un espacio de nombres, ese espacio de nombres se busca en el identificador derecho.
Un qualified_alias_member tiene una de estas dos formas:
N::I<A₁, ..., Aₑ>
, dondeN
yI
representan identificadores, y<A₁, ..., Aₑ>
es una lista de argumentos de tipo. (e
siempre es al menos uno).N::I
, dondeN
yI
representan identificadores. (En este caso,e
se considera cero).
Con esta notación, el significado de un qualified_alias_member se determina de la siguiente manera:
- Si
N
es el identificadorglobal
, se buscaI
en el espacio de nombres global :- Si el espacio de nombres global contiene un espacio de nombres denominado
I
ye
es cero, el qualified_alias_member hace referencia a ese espacio de nombres. - De lo contrario, si el espacio de nombres global contiene un tipo no genérico denominado
I
ye
es cero, el qualified_alias_member hace referencia a ese tipo. - De lo contrario, si el espacio de nombres global contiene un tipo denominado
I
que tienee
parámetros de tipo, el qualified_alias_member hace referencia a ese tipo construido con los argumentos de tipo especificados. - De lo contrario, el qualified_alias_member no está definido y se produce un error en tiempo de compilación.
- Si el espacio de nombres global contiene un espacio de nombres denominado
- De lo contrario, a partir de la declaración de espacio de nombres (§14.3) que contiene inmediatamente el qualified_alias_member (si existe), continuando con cada declaración de espacio de nombres envolvente (si existe) y finalizando con la unidad de compilación que contiene el qualified_alias_member, se evalúan los pasos siguientes hasta que se encuentra una entidad:
- Si la declaración de espacio de nombres o la unidad de compilación contiene un using_alias_directive que asocia N a un tipo, el qualified_alias_member no está definido y se produce un error en tiempo de compilación.
- De lo contrario, si la declaración de espacio de nombres o la unidad de compilación contiene un extern_alias_directive o using_alias_directive que se asocia
N
a un espacio de nombres, a continuación:- Si el espacio de nombres asociado a
N
contiene un espacio de nombres denominadoI
ye
es cero, el qualified_alias_member hace referencia a ese espacio de nombres. - De lo contrario, si el espacio de nombres asociado a
N
contiene un tipo no genérico denominadoI
ye
es cero, el qualified_alias_member hace referencia a ese tipo. - De lo contrario, si el espacio de nombres asociado a
N
contiene un tipo denominadoI
que tienee
parámetros de tipo, el qualified_alias_member hace referencia a ese tipo construido con los argumentos de tipo especificados. - De lo contrario, el qualified_alias_member no está definido y se produce un error en tiempo de compilación.
- Si el espacio de nombres asociado a
- De lo contrario, el qualified_alias_member no está definido y se produce un error en tiempo de compilación.
Ejemplo: en el 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; } }
se hace referencia a la clase
A
conglobal::A
y se hace referencia al tipoSystem.Net.Sockets.Socket
conS::Socket
. El usoA.x
de yS.Socket
en su lugar habría provocado errores en tiempo de compilación porqueA
yS
se habrían resuelto en los parámetros.ejemplo final
Nota: El identificador
global
tiene un significado especial solo cuando se usa como identificador izquierdo de un qualified_alias_name. No es una palabra clave y no es en sí mismo un alias; es una palabra clave contextual (§6.4.4). En el 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.A
produce un error en tiempo de compilación, ya que no hay ninguna entidad denominadaglobal
en el ámbito. Si alguna entidad denominada global estuviera en el ámbito,global
englobal.A
habría resuelto esa entidad.El uso
global
de como identificador izquierdo de un qualified_alias_member siempre provoca una búsqueda en elglobal
espacio de nombres, incluso si hay un alias con el nombreglobal
. En el 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.A
se resuelve enMyGlobalTypes.A
yglobal::A
se resuelve en la claseA
en el espacio de nombres global.nota final
14.8.2 Unicidad de alias
Cada unidad de compilación y cuerpo del espacio de nombres tiene un espacio de declaración independiente para alias extern y el uso de alias. Por lo tanto, aunque el nombre de un alias extern o el uso de alias debe ser único dentro del conjunto de alias extern y el uso de alias declarados en el cuerpo de la unidad de compilación o espacio de nombres inmediatamente que contiene, se permite que un alias tenga el mismo nombre que un tipo o espacio de nombres siempre que solo se use con el ::
calificador.
Ejemplo: En lo siguiente:
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 } }
el nombre
A
tiene dos significados posibles en el segundo cuerpo del espacio de nombres porque tanto la claseA
como el aliasA
using están en el ámbito. Por este motivo, el uso deA
en el nombreA.Stream
completo es ambiguo y hace que se produzca un error en tiempo de compilación. Sin embargo, el uso deA
con el::
calificador no es un error porqueA
solo se busca como alias de espacio de nombres.ejemplo final
ECMA C# draft specification