Partage via


Directive d'utilisation globale

Remarque

Cet article est une spécification de fonctionnalité. La spécification sert de document de conception pour la fonctionnalité. Il inclut les modifications de spécification proposées, ainsi que les informations nécessaires pendant la conception et le développement de la fonctionnalité. Ces articles sont publiés jusqu’à ce que les modifications de spécification proposées soient finalisées et incorporées dans la spécification ECMA actuelle.

Il peut y avoir des différences entre la spécification de la fonctionnalité et l’implémentation terminée. Ces différences sont consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).

Vous pouvez en savoir plus sur le processus d’adoption des speclets de fonctionnalités dans la norme de langage C# dans l’article sur les spécifications .

Problème phare : https://github.com/dotnet/csharplang/issues/3428

La syntaxe d’une directive using est étendue avec un mot clé global facultatif qui peut précéder le mot clé 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 ';'
    ;
  • Les global_using_directives ne sont autorisées qu'au niveau de l’unité de compilation (et ne peuvent pas être utilisées au sein d'une déclaration d’espace de noms, namespace_declaration).
  • Les global_using_directives, le cas échéant, doivent précéder les using_directives.
  • L’étendue des global_using_directives s’étend sur les déclarations des membres de l’espace de noms, namespace_member_declaration, de toutes les unités de compilation au sein du programme. L’étendue d’une global_using_directive n’inclut pas spécifiquement d’autres global_using_directives. Ainsi, les global_using_directives homologues ou celles d’une unité de compilation différente ne s’affectent pas mutuellement, et l’ordre dans lequel elles sont écrites n’a pas d’importance. L’étendue d’une global_using_directive n’inclut pas spécifiquement les using_directives qui se trouvent immédiatement dans une unité de compilation du programme.

L’effet de l’ajout d’un global_using_directive à un programme peut être considéré comme l’effet de l’ajout d’une using_directive similaire qui se résout en un même espace de noms ou type cible sur chaque unité de compilation du programme. Toutefois, la cible de une global_using_directive est résolue dans le contexte de l’unité de compilation qui la contient.

§7.7 Étendues

Voici les points pertinents avec des propositions d’ajout (qui figurent en gras) :

  • L’étendue du nom défini par une extern_alias_directive s’étend sur les global_using_directives, les using_directives, les global_attributes et les namespace_member_declarations du corps de l’unité de compilation ou de l’espace de noms qu’elle contient immédiatement. Une extern_alias_directive n'apporte pas de nouveaux membres à l’espace de déclaration sous-jacent. En d’autres termes, une extern_alias_directive n’est pas transitive, mais affecte uniquement l’unité de compilation ou le corps de l’espace de noms dans lequel il se produit.
  • L’étendue d’un nom défini ou importé par une global_using_directive s’étend sur les global_attributes et les namespace_member_declarations de toutes les compilation_units du programme.

§7.8 Noms des types et des espaces de noms

L'algorithme déterminant la signification d'un namespace_or_type_name est modifié comme suit.

Voici le point pertinent avec des propositions d’ajout (qui figurent en gras) :

  • Si le namespace_or_type_name est de la forme I ou de la forme I<A1, ..., Ak>:
    • Si K est égal à zéro et que la namespace_or_type_name apparaît dans une déclaration de méthode générique (§15.6) et si cette déclaration inclut un paramètre de type (§15.2.3) avec le nom I, la namespace_or_type_name fait référence à ce paramètre de type.
    • Sinon, si le namespace_or_type_name apparaît dans une déclaration de type, pour chaque type d’instance T (§15.3.2), en commençant par le type d’instance de cette déclaration de type et en continuant avec le type d’instance de chaque classe ou déclaration de struct englobante (le cas échéant) :
      • Si K est égal à zéro et que la déclaration de T inclut un paramètre de type portant le nom I, le namespace_or_type_name fait référence à ce paramètre de type.
      • Sinon, si le namespace_or_type_name apparaît dans le corps de la déclaration de type, et que T ou l’un de ses types de base contiennent un type accessible imbriqué ayant un nom I et K paramètres de type, le namespace_or_type_name fait référence à ce type construit avec les arguments de type donnés. S’il existe plusieurs types de ce type, le type déclaré dans le type le plus dérivé est sélectionné. Notez que les membres non de type (constantes, champs, méthodes, propriétés, indexeurs, opérateurs, constructeurs d’instances, destructeurs et constructeurs statiques) et les membres de type avec un nombre différent de paramètres de type sont ignorés lors de la détermination de la signification de la namespace_or_type_name.
    • Si les étapes précédentes n’ont pas réussi, pour chaque espace de noms N, en commençant par l’espace de noms dans lequel se produit le namespace_or_type_name, en continuant avec chaque espace de noms englobant (le cas échéant) et en se terminant par l’espace de noms global, les étapes suivantes sont évaluées jusqu’à ce qu’une entité se trouve :
      • Si K est égal à zéro et I est le nom d’un espace de noms dans N, puis :
        • Si l’emplacement où namespace_or_type_name intervient est entouré d’une déclaration d’espace de noms pour N et que la déclaration d’espace de noms contient une extern_alias_directive ou une using_alias_directive qui associe le nom I à un espace de noms ou à un type, ou si toute déclaration d’espace de noms pour N dans le programme contient une global_using_alias_directive qui associe le nom I à un espace de noms ou un type, namespace_or_type_name est ambigu, et une erreur au moment de la compilation se produit.
        • Sinon, le namespace_or_type_name fait référence à l’espace de noms nommé I dans N.
      • Sinon, si N contient un type accessible ayant le nom I et les paramètres de type K, puis :
        • Si K correspond à zéro et si l’emplacement où namespace_or_type_name intervient est entouré d’une déclaration d’espace de noms pour N et que la déclaration d’espace de noms contient une extern_alias_directive ou une using_alias_directive qui associe le nom I à un espace de noms ou à un type, ou si toute déclaration d’espace de noms pour N dans le programme contient une global_using_alias_directive qui associe le nom I à un espace de noms ou un type, namespace_or_type_name est ambigu, et une erreur au moment de la compilation se produit.
        • Sinon, le namespace_or_type_name fait référence au type construit avec les arguments de type donnés.
      • Sinon, si l'emplacement où se trouve namespace_or_type_name est entouré d'une déclaration d'espace de noms pour N :
        • Si K est égal à zéro et que la déclaration d’espace de noms contient un extern_alias_directive ou using_alias_directive qui associe le nom I à un espace de noms ou un type importé, ou toute déclaration d’espace de noms pour N dans le programme contient un global_using_alias_directive qui associe le nom I à un espace de noms ou un type importé, ensuite le namespace_or_type_name fait référence à cet espace de noms ou à ce type.
        • Sinon, si les espaces de noms et les déclarations de type importés par les using_namespace_directives et les using_alias_directives de la déclaration d’espace de noms et les espaces de noms et les déclarations de type importés par les global_using_namespace_directives et les global_using_static_directives d’une déclaration d’espace de noms pour N dans le programme contiennent exactement un type accessible ayant le nom I et les paramètres de type K, alors le namespace_or_type_name fait référence à ce type construit avec les arguments de type donnés.
        • Sinon, si les espaces de noms et déclarations de type importés par les using_namespace_directives et les using_alias_directives de la déclaration d’espace de noms et si les espaces de noms et les déclarations de type importés par les global_using_namespace_directives et les global_using_static_directives de toute déclaration d’espace de noms pour N dans le programme contiennent plusieurs types accessibles ayant le nom I et les paramètres de type K, namespace_or_type_name est ambigu et une erreur se produit.
    • Sinon, le namespace_or_type_name n’est pas défini et une erreur au moment de la compilation se produit.

Noms simples §12.8.4

Les modifications sont apportées aux règles d’évaluation de simple_name de la manière suivante.

Voici le point pertinent avec des propositions d’ajout (qui figurent en gras) :

  • Sinon, pour chaque espace de noms N, en commençant par l’espace de noms dans lequel se produit l'simple_name, en continuant avec chaque espace de noms englobant (le cas échéant) et en se terminant par l’espace de noms global, les étapes suivantes sont évaluées jusqu’à ce qu’une entité se trouve :
    • Si K est égal à zéro et I est le nom d’un espace de noms dans N, puis :
      • Si l’emplacement où simple_name intervient est entouré d’une déclaration d’espace de noms pour N et que la déclaration d’espace de noms contient une extern_alias_directive ou une using_alias_directive qui associe le nom I à un espace de noms ou à un type, ou si toute déclaration d’espace de noms pour N dans le programme contient une global_using_alias_directive qui associe le nom I à un espace de noms ou un type, simple_name est ambigu, et une erreur au moment de la compilation se produit.
      • Sinon, le simple_name fait référence à l’espace de noms nommé I dans N.
    • Sinon, si N contient un type accessible ayant le nom I et les paramètres de type K, puis :
      • Si K correspond à zéro et si l’emplacement où simple_name intervient est entouré d’une déclaration d’espace de noms pour N et que la déclaration d’espace de noms contient une extern_alias_directive ou une using_alias_directive qui associe le nom I à un espace de noms ou à un type, ou si toute déclaration d’espace de noms pour N dans le programme contient une global_using_alias_directive qui associe le nom I à un espace de noms ou un type, simple_name est ambigu, et une erreur au moment de la compilation se produit.
      • Sinon, le namespace_or_type_name fait référence au type construit avec les arguments de type donnés.
    • Sinon, si l’emplacement où apparaît l'simple_name est entouré d’une déclaration d’espace de noms pour N:
      • Si K est égal à zéro et que la déclaration d’espace de noms contient un extern_alias_directive ou using_alias_directive qui associe le nom I à un espace de noms ou un type importé, ou toute déclaration d’espace de noms pour N dans le programme contient un global_using_alias_directive qui associe le nom I à un espace de noms ou un type importé, ensuite le simple_name fait référence à cet espace de noms ou à ce type.
      • Sinon, si les espaces de noms et les déclarations de type importés par les using_namespace_directives et les using_static_directives de la déclaration d’espace de noms et si les espaces de noms et les déclarations de type importés par les global_using_namespace_directives et les global_using_static_directives de toute déclaration d'espace de noms pour N dans le programme contiennent exactement un type accessible ou un membre statique hors extension avec le nom I et les paramètres de type K, simple_name se réfère à ce type ou membre construit avec les arguments de type donnés.
      • Sinon, si les espaces de noms et les types importés par les using_namespace_directives de la déclaration d’espace de noms et si les espaces de noms et les déclarations de type importés par les global_using_namespace_directives et les global_using_static_directives de toute déclaration d’espace de noms pour N dans le programme contiennent plusieurs types accessibles ou membres statiques hors méthode d’extension, ayant le nom I et les paramètres de type K, simple_name est ambigu et une erreur se produit.

Appels de méthode d’extension §12.8.10.3

Les modifications sont apportées à l’algorithme pour trouver la meilleure type_nameC comme suit. Voici le point pertinent avec des propositions d’ajout (qui figurent en gras) :

  • À compter de la déclaration d’espace de noms englobante la plus proche, en continuant avec chaque déclaration d’espace de noms englobante et en se terminant par l’unité de compilation contenante, des tentatives successives sont effectuées pour rechercher un ensemble candidat de méthodes d’extension :
    • Si l’espace de noms ou l’unité de compilation donné contient directement des déclarations de type non génériques Ci avec des méthodes d’extension éligibles Mj, l’ensemble de ces méthodes d’extension est l’ensemble de candidats.
    • Si les types Ci importés par des using_static_declarations et déclarés directement dans des espaces de noms importés par des using_namespace_directives dans l’espace de noms ou l’unité de compilation donnés et si l’unité de compilation contenante est contactée, et que les types importés par des global_using_static_declarations et déclarés directement dans des espaces de noms importés par des global_using_namespace_directives dans le programme contiennent directement des méthodes d’extension éligibles Mj, l’ensemble de ces méthodes d’extension constitue l’ensemble de candidats.

Unités de compilation §14.2

Une compilation_unit définit la structure globale d’un fichier source. Une unité de compilation se compose de zéro ou plusieurs global_using_directives suivies de zéro ou plusieurs using_directives suivies de zéro ou plusieurs global_attributes suivis de zéro ou plusieurs namespace_member_declarations.

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

Un programme C# se compose d’une ou plusieurs unités de compilation, chacune contenue dans un fichier source distinct. Lorsqu’un programme C# est compilé, toutes les unités de compilation sont traitées ensemble. Ainsi, les unités de compilation peuvent dépendre les unes des autres, éventuellement de manière circulaire.

Les global_using_directives d’une unité de compilation affectent les global_attributes et les namespace_member_declarations de toutes les unités de compilation du programme.

Alias externes §14.4

L’étendue d’une extern_alias_directive s’étend sur les global_using_directives, les using_directives, les global_attributes et les namespace_member_declarations du corps de l’unité de compilation ou de l’espace de noms qu’elle contient immédiatement.

Utilisation de directives d’alias §14.5.2

L’ordre dans lequel les using_alias_directives sont écrites n’a aucune importance, et la résolution de namespace_or_type_name référencée par une using_alias_directive n’est pas affectée par la using_alias_directive elle-même ni par d’autres using_directives dans le corps de l’unité de compilation ou de l’espace de noms qu’elle contient immédiatement, et, si la using_alias_directive est immédiatement contenue dans une unité de compilation, n’est pas affectée par les global_using_directives dans le programme. En d'autres termes, le namespace_or_type_name d’une using_alias_directive est résolu comme si le corps de l’unité de compilation ou de l’espace de noms qu’elle contient immédiatement n'avait aucune using_directive et, si la using_alias_directive est directement contenue dans une unité de compilation, comme si le programme n'avait aucune global_using_directive. Toutefois, une using_alias_directive peut être affectée par des extern_alias_directives dans le corps de l’unité de compilation ou de l’espace de noms qu’elle contient immédiatement.

Directives d'utilisation globale des alias

Une global_using_alias_directive introduit un identificateur qui sert d’alias pour un espace de noms ou un type dans le programme.

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

Dans les déclarations de membres présentes dans n’importe quelle unité de compilation d’un programme contenant un global_using_alias_directive, l’identificateur introduit par global_using_alias_directive peut être utilisé pour faire référence à l’espace de noms ou au type spécifié.

L’identificateur d’une global_using_alias_directive doit être unique dans l’espace de déclaration de toute unité de compilation d’un programme contenant la global_using_alias_directive.

Tout comme les membres réguliers, les noms introduits par des global_using_alias_directives sont masqués par des membres nommés de la même façon dans les étendues imbriquées.

L’ordre dans lequel les global_using_alias_directivesont écrits n’a aucune importance, et la résolution des namespace_or_type_name référencées par un global_using_alias_directive n’est pas affectée par le global_using_alias_directive lui-même ou par d’autres global_using_directiveou using_directives dans le programme. En d’autres termes, le namespace_or_type_name d’une global_using_alias_directive est résolu comme si l’unité de compilation qu’elle contient immédiatement n’avait pas de using_directives et que l’ensemble du programme conteneur n’avait pas de global_using_directives. Toutefois, une global_using_alias_directive peut être affectée par des extern_alias_directives dans l’unité de compilation qu’elle contient immédiatement.

Une global_using_alias_directive peut créer un alias pour n’importe quel espace de noms ou type.

L’accès à un espace de noms ou un type par le biais d’un alias génère exactement le même résultat que l’accès à cet espace de noms ou à ce type via son nom déclaré.

L’utilisation d’alias peut nommer un type construit fermé, mais elle ne peut pas nommer une déclaration de type générique si elle ne fournit pas d'arguments de type.

Directives d'utilisation globale des espaces de noms

Une global_using_namespace_directive importe les types contenus dans un espace de noms dans le programme, ce qui permet à l’identificateur de chaque type d’être utilisé sans qualification.

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

Dans les déclarations de membres d’un programme qui contient une global_using_namespace_directive, les types contenus dans l’espace de noms donné peuvent être référencés directement.

Une global_using_namespace_directive importe les types contenus dans l’espace de noms donné, mais n’importe pas spécifiquement les espaces de noms imbriqués.

Contrairement à un global_using_alias_directive, un global_using_namespace_directive peut importer des types dont les identificateurs sont déjà définis dans une unité de compilation du programme. En effet, dans une unité de compilation donnée, les noms importés par n’importe quelle global_using_namespace_directive dans le programme sont masqués par des membres nommés de la même façon dans l’unité de compilation.

Lorsque plusieurs espaces de noms ou types importés par global_using_namespace_directives ou global_using_static_directives dans le même programme contiennent des types portant le même nom, les références à ce nom comme une type_name sont considérées comme ambiguës.

En outre, lorsque plusieurs espaces de noms ou types importés par global_using_namespace_directives ou global_using_static_directives dans le même programme contiennent des types ou des membres du même nom, les références à ce nom en tant que simple_name sont considérées comme ambiguës.

Le namespace_name référencé par une global_using_namespace_directive est résolu de la même façon que le namespace_or_type_name référencé par une global_using_alias_directive. Par conséquent, les global_using_namespace_directives dans le même programme ne s’affectent pas mutuellement et peuvent être écrites dans n’importe quel ordre.

Directives statiques Global Using

Une global_using_static_directive importe les types imbriqués et les membres statiques contenus directement dans une déclaration de type dans le programme conteneur, ce qui permet à l’identificateur de chaque membre et type d’être utilisé sans qualification.

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

Dans les déclarations de membre d’un programme qui contient un global_using_static_directive, les types imbriqués accessibles et les membres statiques (à l’exception des méthodes d’extension) contenus directement dans la déclaration du type donné peuvent être référencés directement.

Une global_using_static_directive n’importe pas directement les méthodes d’extension en tant que méthodes statiques, mais les rend disponibles pour l’appel de méthodes d’extension.

Une global_using_static_directive importe uniquement les membres et les types déclarés directement dans le type donné, et non les membres et les types déclarés dans les classes de base.

Les ambiguïtés entre plusieurs global_using_namespace_directives et global_using_static_directives sont abordées dans la section relative aux global_using_namespace_directives (ci-dessus).

Membre d’alias qualifié §14.8

Des modifications ont été apportées à l'algorithme déterminant la signification d’un qualified_alias_member de la manière suivante.

Voici le point pertinent avec des propositions d’ajout (qui figurent en gras) :

  • Sinon, à partir de la déclaration d’espace de noms (§14.3) contenant immédiatement le qualified_alias_member (le cas échéant), en continuant avec chaque déclaration d’espace de noms englobante (le cas échéant) et en se terminant par l’unité de compilation contenant le qualified_alias_member, les étapes suivantes sont évaluées jusqu’à ce qu’une entité se trouve :

    • Si la déclaration d’espace de noms ou l’unité de compilation contient un using_alias_directive qui associe N à un type, ou, à l’atteinte d'une unité de compilation, le programme contient un global_using_alias_directive qui associe N à un type, alors l'qualified_alias_member n’est pas défini et une erreur de compilation se produit.
    • Sinon, si la déclaration de l'espace de noms ou l’unité de compilation contient une extern_alias_directive ou une using_alias_directive qui associe N à un espace de noms, *ou, lorsqu’une unité de compilation est contactée, si le programme contient une global_using_alias_directive qui associe N à un espace de noms, alors :
      • Si l’espace de noms associé à N contient un espace de noms nommé I et K est égal à zéro, le qualified_alias_member fait référence à cet espace de noms.
      • Sinon, si l’espace de noms associé à N contient un type non générique nommé I et K est égal à zéro, le qualified_alias_member fait référence à ce type.
      • Sinon, si l’espace de noms associé à N contient un type nommé I qui a K paramètres de type, le qualified_alias_member fait référence à ce type construit avec les arguments de type donnés.
      • Sinon, le qualified_alias_member n’est pas défini et une erreur au moment de la compilation se produit.