Compartir a través de


Directiva de uso global

Nota

Este artículo es una especificación de características. La especificación actúa como documento de diseño de la característica. Incluye cambios de especificación propuestos, junto con la información necesaria durante el diseño y el desarrollo de la característica. Estos artículos se publican hasta que se finalizan los cambios de especificación propuestos e se incorporan en la especificación ECMA actual.

Puede haber algunas discrepancias entre la especificación de características y la implementación completada. Esas diferencias se recogen en las notas de la reunión de diseño de lenguaje (LDM) correspondientes.

Puede obtener más información sobre el proceso de adopción de especificaciones de características en el estándar del lenguaje C# en el artículo sobre las especificaciones de .

Problema del campeón: https://github.com/dotnet/csharplang/issues/3428

La sintaxis de una directiva using se amplía con la inclusión opcional de una palabra clave global, que puede preceder a la palabra clave 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 ';'
    ;
  • Las directivas global_using_directive solo están permitidas a nivel de unidad de compilación (no pueden utilizarse dentro de una namespace_declaration).
  • Las directivas global_using_directive, si existen, deben preceder a cualquier directiva using_directive.
  • El ámbito de una directiva global_using_directive se extiende a las namespace_member_declaration de todas las unidades de compilación del programa. El ámbito de una directiva global_using_directive no incluye específicamente otras directivas global_using_directive. Por lo tanto, las directivas global_using_directive homologas o las de una unidad de compilación diferente no se afectan entre sí, y el orden en que se escriben es insignificante. El ámbito de una directiva global_using_directive no incluye específicamente las directivas using_directive contenidas inmediatamente en cualquier unidad de compilación del programa.

El efecto de añadir una directiva global_using_directive a un programa puede considerarse como el efecto de añadir una directiva using_directive similar que resuelva al mismo espacio de nombres o tipo de destino a cada unidad de compilación del programa. Sin embargo, el objetivo de una directiva global_using_directive se resuelve en el contexto de la unidad de compilación que la contiene.

§7.7 Ámbitos

Estos son los puntos relevantes con las adiciones propuestas (que están en negrita):

  • El ámbito del nombre definido por una directiva extern_alias_directive se extiende sobre las directivas global_using_directive,using_directive, global_attributes y namespace_member_declaration de su unidad de compilación o cuerpo de espacio de nombres inmediatamente contenedor. Una directiva extern_alias_directive no aporta ningún miembro nuevo al espacio de declaración subyacente. En otras palabras, un extern_alias_directive no es transitivo, sino que solo afecta al cuerpo de la unidad de compilación o del espacio de nombres en el que se produce.
  • El ámbito de un nombre definido o importado por una directiva global_using_directive se extiende sobre los global_attributes y las namespace_member_declaration de todas las compilation_unit en el programa.

Sección 7.8 Nombres de espacios de nombres y tipos

Los cambios se realizan en el algoritmo que determina el significado de un namespace_or_type_name como se indica a continuación.

Este es el punto relevante con las adiciones propuestas (en negrita):

  • Si el namespace_or_type_name es de la forma I o de la forma I<A1, ..., Ak>:
    • Si K es cero y el namespace_or_type_name aparece dentro de una declaración de método genérico (§15.6) y si esa declaración incluye un parámetro de tipo (§15.2.3) con el nombre I, el namespace_or_type_name hace referencia a ese parámetro de tipo.
    • De lo contrario, si el namespace_or_type_name aparece dentro de una declaración de tipo, entonces para cada tipo de instancia T (sección 15.3.2), empezando por el tipo de instancia de esa declaración de tipo y continuando con el tipo de instancia de cada declaración de clase o estructura adjunta (si existe):
      • Si K es cero y la declaración de T incluye un parámetro de tipo con el nombre I, el namespace_or_type_name hace referencia a ese parámetro de tipo.
      • De lo contrario, si el namespace_or_type_name aparece dentro del cuerpo de la declaración de tipo, y T o cualquiera de sus tipos base contienen un tipo accesible anidado con un nombre I y parámetros de tipo K, el namespace_or_type_name hace referencia a ese tipo construido con los argumentos de tipo especificados. Si hay más de un tipo de este tipo, se selecciona el tipo declarado en el tipo más derivado. Tenga en cuenta que los miembros que no son de tipo (constantes, campos, métodos, propiedades, indexadores, operadores, constructores de instancia, destructores y constructores estáticos) y los miembros de tipo con un número diferente de parámetros de tipo se omiten al determinar el significado de la namespace_or_type_name.
    • Si los pasos anteriores no se realizaron correctamente, para cada espacio de nombres N, empezando por el espacio de nombres en el que se produce el namespace_or_type_name, continuando con cada espacio de nombres envolvente (si existe) y finalizando con el espacio de nombres global, se evalúan los pasos siguientes hasta que se encuentra una entidad:
      • Si K es cero y I es el nombre de un espacio de nombres en N, a continuación:
        • Si el lugar donde aparece namespace_or_type_name está encerrado por una declaración de espacio de nombres para N y la declaración de espacio de nombres contiene una directiva extern_alias_directive o using_alias_directive que asocia el nombre I con un espacio de nombres o tipo, o cualquier declaración de espacio de nombres para N en el programa contiene una directiva global_using_alias_directive que asocia el nombre I con un espacio de nombres o tipo, entonces namespace_or_type_name es ambiguo y se produce un error de compilación.
        • De lo contrario, el namespace_or_type_name hace referencia al espacio de nombres denominado I en N.
      • De lo contrario, si N contiene un tipo accesible que tiene el nombre I y K parámetros de tipo, entonces:
        • Si K es cero y el lugar donde aparece namespace_or_type_name está encerrado por una declaración de espacio de nombres para N y la declaración de espacio de nombres contiene una directiva extern_alias_directive o using_alias_directive que asocia el nombre I con un espacio de nombres o tipo, o cualquier declaración de espacio de nombres para N en el programa contiene una directiva global_using_alias_directive que asocia el nombre I con un espacio de nombres o tipo, entonces namespace_or_type_name es ambiguo y se produce un error de compilación.
        • De lo contrario, el namespace_or_type_name hace referencia al tipo construido con los argumentos de tipo especificados.
      • De lo contrario, si la ubicación donde ocurre el namespace_or_type_name está incluido en una declaración de espacio de nombres para N:
        • Si K es cero y la declaración de espacio de nombres contiene una directiva extern_alias_directive o using_alias_directive que asocia el nombre I con un espacio de nombres o tipo importado, o cualquier declaración de espacio de nombres para N en el programa contiene una directiva global using_alias_directive que asocia el nombre I con un espacio de nombres o tipo importado, entonces el namespace_or_type_name se refiere a ese espacio de nombres o tipo.
        • En caso contrario, si los espacios de nombres y las declaraciones de tipos importados por las directivas using_namespace_directive y using_alias_directive de la declaración de espacio de nombres y los espacios de nombres y las declaraciones de tipos importados por las directivas global_using_namespace_directive y global_using_static_directive de cualquier declaración de espacio de nombres para N en el programa contienen exactamente un tipo accesible que tiene nombre I y parámetros de tipo K, entonces el namespace_or_type_name se refiere a ese tipo construido con los argumentos de tipo dados.
        • En caso contrario, si los espacios de nombres y las declaraciones de tipos importados por las directivas using_namespace_directive y using_alias_directive de la declaración de espacio de nombres y los espacios de nombres y las declaraciones de tipos importados por las directivas global_using_namespace_directive y global_using_static_directive de cualquier declaración de espacio de nombres para N en el programa contienen más de un tipo accesible que tiene nombre I y parámetros de tipo K, entonces el namespace_or_type_name es ambiguo y se produce un error.
    • De lo contrario, el namespace_or_type_name no está definido y se produce un error en tiempo de compilación.

Nombres simples §12.8.4

Los cambios se realizan en las reglas de evaluación de simple_name como se indica a continuación.

Este es el punto relevante con las adiciones propuestas (en negrita):

  • De lo contrario, para cada espacio de nombres N, empezando por el espacio de nombres en el que se produce el simple_name, continuando con cada espacio de nombres envolvente (si existe) y finalizando con el espacio de nombres global, se evalúan los pasos siguientes hasta que se encuentra una entidad:
    • Si K es cero y I es el nombre de un espacio de nombres en N, a continuación:
      • Si el lugar donde aparece simple_name está encerrado por una declaración de espacio de nombres para N y la declaración de espacio de nombres contiene una directiva extern_alias_directive o using_alias_directive que asocia el nombre I con un espacio de nombres o tipo, o cualquier declaración de espacio de nombres para N en el programa contiene una directiva global_using_alias_directive que asocia el nombre I con un espacio de nombres o tipo, entonces simple_name es ambiguo y se produce un error de compilación.
      • De lo contrario, el simple_name hace referencia al espacio de nombres denominado I en N.
    • De lo contrario, si N contiene un tipo accesible llamado I y K parámetros de tipo, entonces:
      • Si K es cero y el lugar donde aparece simple_name está encerrado por una declaración de espacio de nombres para N y la declaración de espacio de nombres contiene una directiva extern_alias_directive o using_alias_directive que asocia el nombre con un espacio de nombres o tipo I, o cualquier declaración de espacio de nombres para N en el programa contiene una directiva global_using_alias_directive que asocia el nombre I con un espacio de nombres o tipo, entonces simple_name es ambiguo y se produce un error de compilación.
      • De lo contrario, el namespace_or_type_name hace referencia al tipo construido con los argumentos de tipo especificados.
    • De lo contrario, si la ubicación donde ocurre el simple_name está incluida en una declaración de espacio de nombres para N:
      • Si K es cero y la declaración de espacio de nombres contiene un extern_alias_directive o using_alias_directive que asocia el nombre I con un espacio de nombres o tipo importado, o cualquier declaración de espacio de nombres para N en el programa contiene un global_using_alias_directive que asocia el nombre I con un espacio de nombres o tipo importados, entonces el simple_name hace referencia a ese espacio de nombres o tipo.
      • En caso contrario, si los espacios de nombres y las declaraciones de tipos importados por las directivas using_namespace_directive y using_static_directive de la declaración de espacio de nombres y los espacios de nombres y las declaraciones de tipos importados por las directivas global_using_namespace_directive y global_using_static_directive de cualquier declaración de espacio de nombres para N en el programa contienen exactamente un tipo accesible o miembro estático sin extensión que tiene nombre I y parámetros de tipo K, entonces el simple_name se refiere a ese tipo o miembro construido con los argumentos de tipo dados.
      • De lo contrario, si los espacios de nombres y tipos importados por las using_namespace_directive de la declaración de espacio de nombres y los espacios de nombres y declaraciones de tipos importados por las global_using_namespace_directive y global_using_static_directive de cualquier declaración de espacio de nombres para N en el programa contienen más de un tipo accesible o miembro estático no método de extensión que tiene nombre I y parámetros de tipo K, entonces el simple_name es ambiguo y se produce un error.

Invocaciones de métodos de extensión Sección 12.8.10.3

Los cambios se realizan en el algoritmo para encontrar el mejor type_nameC como se indica a continuación. Este es el punto relevante con las adiciones propuestas (en negrita):

  • Empezando por la declaración de espacio de nombres más cercana, continuando con cada declaración de espacio de nombres y terminando con la unidad de compilación contenedora, se realizan intentos sucesivos para encontrar un conjunto candidato de métodos de extensión:
    • Si el espacio de nombres o la unidad de compilación especificados contiene directamente declaraciones de tipos no genéricos Ci con métodos de extensión aptos Mj, el conjunto de esos métodos de extensión es el conjunto candidato.
    • Si los tipos Ci importados por using_static_declarations y declarados directamente en espacios de nombres importados por using_namespace_directives en el espacio de nombres o unidad de compilación dados y, si se llega a la unidad de compilación contenedora , importados por global_using_static_declarations y declarados directamente en espacios de nombres importados por global_using_namespace_directive en el programa contienen directamente métodos de extensión elegibles Mj, entonces el conjunto de esos métodos de extensión es el conjunto candidato.

Unidades de compilación §14.2

Un compilation_unit define la estructura general de un archivo de origen. Una unidad de compilación consta de cero o más global_using_directive seguidas de cero o más using_directive seguidas de cero o más global_attribute seguidas de cero o más namespace_member_declaration.

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

Un programa de C# consta de una o varias unidades de compilación, cada una contenida en un archivo de código fuente independiente. 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.

Las global_using_directive de una unidad de compilación afectan a los global_attributes y namespace_member_declaration de todas las unidades de compilación del programa.

Aliases externos §14.4

El ámbito de una extern_alias_directive se extiende sobre las global_using_directive, using_directive, global_attributes y namespace_member_declaration de su unidad de compilación o cuerpo de espacio de nombres inmediatamente contenedor.

Uso de directivas de alias Sección 14.5.2

El orden en que se escriben las using_alias_directive no tiene importancia, y la resolución del namespace_or_type_name al que hace referencia una using_alias_directive no se ve afectada por la propia using_alias_directive ni por otras using_directive de la unidad de compilación o cuerpo de espacio de nombres que la contiene inmediatamente, y, si la using_alias_directive está contenida inmediatamente en una unidad de compilación, no se ve afectada por las global_using_directive del programa. En otras palabras, el namespace_or_type_name de una using_alias_directive se resuelve como si la unidad de compilación o cuerpo de espacio de nombres que lo contiene inmediatamente no tuviera using_directive y, si la using_alias_directive está contenida inmediatamente en una unidad de compilación, el programa no tuviera global_using_directive. Una using_alias_directive puede, sin embargo, verse afectada por extern_alias_directive en la unidad de compilación inmediatamente contenedora o en el cuerpo del espacio de nombres.

Directivas alias de uso global

Una global_using_alias_directive introduce un identificador que sirve como alias para un espacio de nombres o tipo dentro del programa.

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

Dentro de las declaraciones de miembros de cualquier unidad de compilación de un programa que contenga una global_using_alias_directive, el identificador introducido por la global_using_alias_directive puede utilizarse para hacer referencia al espacio de nombres o tipo dado.para hacer referencia al espacio de nombres o el tipo especificados.

El identificador de un global_using_alias_directive debe ser único dentro del espacio de declaración de cualquier unidad de compilación de un programa que contenga el global_using_alias_directive.

El identifier de una global_using_alias_directive debe ser único dentro del espacio de declaración de cualquier unidad de compilación de un programa que contenga la global_using_alias_directive.

El orden en el que se escriben las global_using_alias_directive no tiene importancia, y la resolución del namespace_or_type_name al que hace referencia una global_using_alias_directive no se ve afectada por la propia global_using_alias_directive ni por otras global_using_directives o using_directive del programa. En otras palabras, el namespace_or_type_name de una global_using_alias_directive se resuelve como si la unidad de compilación que la contiene inmediatamente no tuviera using_directive y todo el programa que la contiene no tuviera global_using_directive. Sin embargo, una global_using_alias_directive puede verse afectada por extern_alias_directive en la unidad de compilación que la contiene inmediatamente.

Una directiva global_using_alias_directive puede crear un alias para cualquier espacio de nombres o tipo.

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.

El uso de alias puede nombrar un tipo construido cerrado, pero no puede nombrar una declaración de tipo genérico no enlazado sin suministrar argumentos de tipo.

Directivas de espacio de nombres de uso global

Una directiva global_using_namespace_directive importa al programa los tipos contenidos en un espacio de nombres, permitiendo utilizar el identificador de cada tipo sin cualificación.

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

Dentro de las declaraciones de miembros de un programa que contiene una directiva global_using_namespace_directive, se puede hacer referencia directa a los tipos contenidos en el espacio de nombres dado.

Una directiva global_using_namespace_directive importa los tipos contenidos en el espacio de nombres dado, pero específicamente no importa espacios de nombres anidados.

A diferencia de un global_using_alias_directive, un global_using_namespace_directive puede importar tipos cuyos identificadores ya están definidos dentro de una unidad de compilación del programa. En efecto, en una unidad de compilación determinada, los nombres importados por cualquier global_using_namespace_directive del programa están ocultos por miembros con nombre similar en la unidad de compilación.

Cuando más de un espacio de nombres o tipo importado por global_using_namespace_directives o global_using_static_directives del mismo programa contienen tipos con el mismo nombre, las referencias a ese nombre como un type_name se consideran ambiguas.

Además, cuando más de un espacio de nombres o tipo importado por global_using_namespace_directives o global_using_static_directives en el mismo programa contienen tipos o miembros con el mismo nombre, las referencias a ese nombre como una simple_name son consideradas ambiguas.

El namespace_name referenciado por una global_using_namespace_directive se resuelve de la misma manera que el namespace_or_type_name referenciado por una global_using_alias_directive. Por lo tanto, directiva global_using_namespace_directive en el mismo programa no se afectan entre sí y pueden escribirse en cualquier orden.

Uso global de directivas estáticas

Una directiva global_using_static_directive importa los tipos anidados y los miembros estáticos contenidos directamente en una declaración de tipo en el programa que la contiene, lo que permite utilizar el identificador de cada miembro y tipo sin cualificación.

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

Dentro de las declaraciones de miembros en un programa que contiene una directiva_global_using_static_directive, los tipos anidados accesibles y los miembros estáticos (excepto los métodos de extensión) contenidos directamente en la declaración del tipo dado pueden ser referenciados directamente.

Una global_using_static_directive específicamente no importa métodos de extensión directamente como métodos estáticos, pero los hace disponibles para la invocación de métodos de extensión.

Un global_using_static_directive solo importa miembros y tipos declarados directamente en el tipo especificado, no miembros y tipos declarados en clases base.

Las ambigüedades entre múltiples global_using_namespace_directive y global_using_static_directive se discuten en la sección para global_using_namespace_directive (arriba).

Miembro de alias cualificado Sección 14.8

Los cambios se realizan en el algoritmo que determina el significado de un qualified_alias_member de la siguiente manera.

Este es el punto relevante con las adiciones propuestas (en negrita):

  • En caso contrario, comenzando por la declaración de espacio de nombres (Sección 14.3) que contiene inmediatamente al qualified_alias_member (si existe), continuando con cada declaración de espacio de nombres que la encierra (si existe) y terminando con la unidad de compilación que contiene al qualified_alias_member, se evalúan los siguientes pasos hasta que se localiza una entidad:

    • Si la declaración de espacio de nombres o la unidad de compilación contiene un using_alias_directive que asocia N con un tipo, o, cuando se alcanza una unidad de compilación, el programa contiene un global_using_alias_directive que asocia N con un tipo, entonces 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 una extern_alias_directive o using_alias_directive que asocia N con un espacio de nombres, *o, cuando se llega a una unidad de compilación, el programa contiene una global_using_alias_directive que asocia N con un espacio de nombres, entonces:
      • Si el espacio de nombres asociado a N contiene un espacio de nombres denominado I y K 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 denominado I y K 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 denominado I que tiene parámetros de tipo K, 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.