14 espaces de noms
14.1 Général
Les programmes C# sont organisés à l’aide d’espaces de noms. Les espaces de noms sont utilisés à la fois comme système d’organisation « interne » pour un programme, et comme système d’organisation « externe », un moyen de présenter des éléments de programme exposés à d’autres programmes.
L’utilisation de directives (§14.5) est fournie pour faciliter l’utilisation des espaces de noms.
14.2 Unités de compilation
Un compilation_unit se compose de zéro ou plusieurs extern_alias_directivesuivis de zéro ou plus de using_directives suivis de zéro ou d’un global_attributes suivi de zéro ou plus de namespace_member_declarations. La compilation_unit définit la structure globale de l’entrée.
compilation_unit
: extern_alias_directive* using_directive* global_attributes?
namespace_member_declaration*
;
Un programme C# se compose d’une ou plusieurs unités de compilation. 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 extern_alias_directived’une unité de compilation affectent les using_directive, les global_attributes et les namespace_member_declarationde cette unité de compilation, mais n’ont aucun effet sur d’autres unités de compilation.
Les using_directived’une unité de compilation affectent les global_attributes et les namespace_member_declarationde cette unité de compilation, mais n’ont aucun effet sur d’autres unités de compilation.
La global_attributes (§22.3) d’une unité de compilation permet la spécification des attributs pour l’assembly et le module cibles. Les assemblys et les modules agissent en tant que conteneurs physiques pour les types. Un assembly peut se composer de plusieurs modules physiquement distincts.
Les namespace_member_declarationde chaque unité de compilation d’un programme contribuent aux membres à un espace de déclaration unique appelé espace de noms global.
Exemple :
// File A.cs: class A {} // File B.cs: class B {}
Les deux unités de compilation contribuent à l’espace de noms global unique, dans ce cas, déclarant deux classes avec les noms complets
A
etB
. Étant donné que les deux unités de compilation contribuent au même espace de déclaration, il aurait été une erreur si chacune contenait une déclaration d’un membre portant le même nom.exemple de fin
14.3 Déclarations d’espace de noms
Un namespace_declaration se compose de l’espace de noms de mot clé, suivi d’un nom et d’un corps d’espace de noms, éventuellement suivis d’un point-virgule.
namespace_declaration
: 'namespace' qualified_identifier namespace_body ';'?
;
qualified_identifier
: identifier ('.' identifier)*
;
namespace_body
: '{' extern_alias_directive* using_directive*
namespace_member_declaration* '}'
;
Une namespace_declaration peut se produire sous la forme d’une déclaration de niveau supérieur dans un compilation_unit ou en tant que déclaration de membre au sein d’une autre namespace_declaration. Lorsqu’un namespace_declaration se produit en tant que déclaration de niveau supérieur dans un compilation_unit, l’espace de noms devient membre de l’espace de noms global. Lorsqu’un namespace_declaration se produit dans une autre namespace_declaration, l’espace de noms interne devient membre de l’espace de noms externe. Dans les deux cas, le nom d’un espace de noms doit être unique dans l’espace de noms conteneur.
Les espaces de noms sont implicitement public
et la déclaration d’un espace de noms ne peut pas inclure de modificateurs d’accès.
Dans un namespace_body, les using_directivefacultatifs importent les noms d’autres espaces de noms, types et membres, ce qui leur permet d’être référencés directement au lieu d’utiliser des noms qualifiés. Les namespace_member_declarationfacultatifs contribuent aux membres à l’espace de déclaration de l’espace de noms. Notez que tous les using_directivedoivent apparaître avant toutes les déclarations de membre.
L’qualified_identifier d’un namespace_declaration peut être un identificateur unique ou une séquence d’identificateurs séparés par des jetons «.
». Ce dernier formulaire permet à un programme de définir un espace de noms imbriqué sans imbrication lexicale de plusieurs déclarations d’espace de noms.
Exemple :
namespace N1.N2 { class A {} class B {} }
est sémantiquement équivalent à
namespace N1 { namespace N2 { class A {} class B {} } }
exemple de fin
Les espaces de noms sont ouverts et deux déclarations d’espace de noms portant le même nom complet (§7.8.2) contribuent au même espace de déclaration (§7.3).
Exemple : dans le code suivant
namespace N1.N2 { class A {} } namespace N1.N2 { class B {} }
les deux déclarations d’espace de noms ci-dessus contribuent au même espace de déclaration, dans ce cas en déclarant deux classes avec les noms qualifiés complets
N1.N2.A
etN1.N2.B
. Étant donné que les deux déclarations contribuent à la même espace de déclaration, il aurait été une erreur si chacune contenait une déclaration d’un membre portant le même nom.exemple de fin
14.4 Directives d’alias extern
Une extern_alias_directive introduit un identificateur qui sert d’alias pour un espace de noms. La spécification de l’espace de noms alias est externe au code source du programme et s’applique également aux espaces de noms imbriqués de l’espace de noms alias.
extern_alias_directive
: 'extern' 'alias' identifier ';'
;
L’étendue d’une extern_alias_directive s’étend sur les using_directive, les global_attributes et les namespace_member_declarationde ses compilation_unit ou namespace_body immédiatement.
Dans un corps d’unité de compilation ou d’espace de noms qui contient un extern_alias_directive, l’identificateur introduit par l’extern_alias_directive peut être utilisé pour référencer l’espace de noms alias. Il s’agit d’une erreur au moment de la compilation pour que l’identificateur soit le mot global
.
L’alias introduit par un extern_alias_directive est très similaire à l’alias introduit par un using_alias_directive. Consultez le §14.5.2 pour plus d’informations sur les extern_alias_directiveet les using_alias_directive.
alias
est un mot clé contextuel (§6.4.4) et n’a qu’une signification particulière lorsqu’il suit immédiatement le extern
mot clé dans un extern_alias_directive.
Une erreur se produit si un programme déclare un alias extern pour lequel aucune définition externe n’est fournie.
Exemple : le programme suivant déclare et utilise deux alias extern et
X
Y
, chacun représentant la racine d’une hiérarchie d’espaces de noms distincte :extern alias X; extern alias Y; class Test { X::N.A a; X::N.B b1; Y::N.B b2; Y::N.C c; }
Le programme déclare l’existence des alias
X
extern etY
, mais les définitions réelles des alias sont externes au programme. Les classes identiques nomméesN.B
peuvent désormais être référencées en tant que etY.N.B
X.N.B
, ou, à l’aide du qualificateur d’alias d’espace de noms,X::N.B
etY::N.B
. exemple de fin
14.5 Utilisation de directives
14.5.1 Général
L’utilisation de directives facilite l’utilisation d’espaces de noms et de types définis dans d’autres espaces de noms. L’utilisation de directives affecte le processus de résolution de noms des namespace_or_type_name (§7.8) et des simple_name(§12.8.4), mais contrairement aux déclarations, les using_directivene contribuent pas aux nouveaux membres aux espaces de déclaration sous-jacents des unités de compilation ou des espaces de noms dans lesquels ils sont utilisés.
using_directive
: using_alias_directive
| using_namespace_directive
| using_static_directive
;
Un using_alias_directive (§14.5.2) introduit un alias pour un espace de noms ou un type.
Un using_namespace_directive (§14.5.3) importe les membres de type d’un espace de noms.
Un using_static_directive (§14.5.4) importe les types imbriqués et les membres statiques d’un type.
L’étendue d’une using_directive s’étend sur la namespace_member_declarations de son corps d’unité de compilation ou d’espace de noms immédiatement. L’étendue d’une using_directive n’inclut pas spécifiquement ses using_directivehomologues. Ainsi, les using_directivehomologues n’affectent pas les uns les autres, et l’ordre dans lequel ils sont écrits est insignifiant. En revanche, l’étendue d’un extern_alias_directive inclut les using_directivedéfinies dans le même corps d’unité de compilation ou d’espace de noms.
14.5.2 Utilisation des directives d’alias
Un using_alias_directive introduit un identificateur qui sert d’alias pour un espace de noms ou un type dans l’unité de compilation ou le corps de l’espace de noms immédiatement englobant.
using_alias_directive
: 'using' identifier '=' namespace_or_type_name ';'
;
Dans les attributs globaux et les déclarations de membre dans un corps d’unité de compilation ou d’espace de noms qui contient un using_alias_directive, l’identificateur introduit par l’using_alias_directive peut être utilisé pour référencer l’espace de noms ou le type donné.
Exemple :
namespace N1.N2 { class A {} } namespace N3 { using A = N1.N2.A; class B: A {} }
Ci-dessus, dans les déclarations de membre dans l’espace
N3
de noms,A
est un alias pourN1.N2.A
, et donc la classeN3.B
dérive de la classeN1.N2.A
. Le même effet peut être obtenu en créant un aliasR
pourN1.N2
et en référençantR.A
:namespace N3 { using R = N1.N2; class B : R.A {} }
exemple de fin
Dans l’utilisation de directives, d’attributs globaux et de déclarations de membres dans un corps d’unité de compilation ou d’espace de noms qui contient un extern_alias_directive, l’identificateur introduit par l’extern_alias_directive peut être utilisé pour référencer l’espace de noms associé.
Exemple : Par exemple :
namespace N1 { extern alias N2; class B : N2::A {} }
Au-dessus, dans les déclarations de membre de l’espace
N1
de noms,N2
il s’agit d’un alias pour un espace de noms dont la définition est externe au code source du programme. La classeN1.B
dérive de la classeN2.A
. Le même effet peut être obtenu en créant un aliasA
pourN2.A
et en référençantA
:namespace N1 { extern alias N2; using A = N2::A; class B : A {} }
exemple de fin
Un extern_alias_directive ou using_alias_directive rend un alias disponible dans un corps d’unité de compilation ou d’espace de noms particulier, mais il ne contribue pas aux nouveaux membres à l’espace de déclaration sous-jacent. En d’autres termes, une directive d’alias n’est pas transitive, mais affecte uniquement l’unité de compilation ou le corps de l’espace de noms dans lequel il se produit.
Exemple : dans le code suivant
namespace N3 { extern alias R1; using R2 = N1.N2; } namespace N3 { class B : R1::A, R2.I {} // Error, R1 and R2 unknown }
les étendues des directives d’alias qui introduisent
R1
etR2
s’étendent uniquement aux déclarations de membre dans le corps de l’espace de noms dans lequel elles sont contenues, de sorte qu’ellesR1
R2
sont inconnues dans la deuxième déclaration d’espace de noms. Toutefois, le fait de placer les directives d’alias dans l’unité de compilation contenant entraîne la disponibilité de l’alias dans les deux déclarations d’espace de noms :extern alias R1; using R2 = N1.N2; namespace N3 { class B : R1::A, R2.I {} } namespace N3 { class C : R1::A, R2.I {} }
exemple de fin
Chaque extern_alias_directive ou using_alias_directive dans un compilation_unit ou namespace_body contribue à un nom à l’espace de déclaration d’alias (§7.3) du compilation_unit ou namespace_body immédiatement englobant. L’identificateur de la directive d’alias doit être unique dans l’espace de déclaration d’alias correspondant. L’identificateur d’alias n’a pas besoin d’être unique dans l’espace de déclaration global ou dans l’espace de déclaration de l’espace de noms correspondant.
Exemple :
extern alias X; extern alias Y; using X = N1.N2; // Error: alias X already exists class Y {} // Ok
L’alias utilisant nommé
X
provoque une erreur, car il existe déjà un alias nomméX
dans la même unité de compilation. La classe nomméeY
n’est pas en conflit avec l’alias extern nomméY
, car ces noms sont ajoutés à des espaces de déclaration distincts. L’ancien est ajouté à l’espace de déclaration globale et celui-ci est ajouté à l’espace de déclaration d’alias pour cette unité de compilation.Lorsqu’un nom d’alias correspond au nom d’un membre d’un espace de noms, l’utilisation de l’un ou l’autre doit être qualifiée de manière appropriée :
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 }
Dans le deuxième corps de l’espace de noms pour
N3
, l’utilisation non qualifiée desB
résultats entraîne une erreur, carN3
contient un membre nomméB
et le corps de l’espace de noms qui déclare également un alias avec un nomB
; de même pourA
. La classeN3.B
peut être référencée en tant queN3.B
ouglobal::N3.B
. L’aliasA
peut être utilisé dans un membre qualifié-alias (§14.8), tel queA::B
. L’aliasB
est essentiellement inutile. Il ne peut pas être utilisé dans un qualified_alias_member , car seuls les alias d’espace de noms peuvent être utilisés dans un qualified_alias_member etB
les alias d’un type.exemple de fin
Tout comme les membres réguliers, les noms introduits par alias_directives sont masqués par des membres nommés de la même façon dans les étendues imbriquées.
Exemple : dans le code suivant
using R = N1.N2; namespace N3 { class R {} class B: R.A {} // Error, R has no member A }
la référence à
R.A
dans la déclaration de causes d’une erreur au moment deB
la compilation, carR
fait référence àN3.R
, et nonN1.N2
.exemple de fin
L’ordre dans lequel les extern_alias_directivesont écrits n’a aucune importance. De même, l’ordre dans lequel les using_alias_directivesont écrits n’a aucune importance, mais toutes les using_alias_directives doivent venir après tous les extern_alias_directives dans le même corps d’unité de compilation ou d’espace de noms. La résolution de la namespace_or_type_name référencée par un using_alias_directive n’est pas affectée par le using_alias_directive lui-même ou par d’autres using_directives dans le corps de l’unité de compilation ou de l’espace de noms contenant immédiatement, mais peut être affectée par des extern_alias_directivedans le corps de l’unité de compilation ou de l’espace de noms contenant immédiatement. En d’autres termes, le namespace_or_type_name d’un using_alias_directive est résolu comme si le corps de l’unité de compilation ou de l’espace de noms contenant immédiatement n’avait pas de using_directives, mais qu’il a le jeu correct de extern_alias_directives.
Exemple : dans le code suivant
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 }
la dernière using_alias_directive génère une erreur au moment de la compilation, car elle n’est pas affectée par la using_alias_directive précédente. La première using_alias_directive n’entraîne pas d’erreur, car l’étendue de l’alias extern X inclut le using_alias_directive.
exemple de fin
Un using_alias_directive peut créer un alias pour n’importe quel espace de noms ou type, y compris l’espace de noms dans lequel il apparaît et n’importe quel espace de noms ou type imbriqué dans cet espace de noms.
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é.
Exemple : Donné
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 } }
les noms
N1.N2.A
,R1.N2.A
et sont équivalents etR2.A
tous font référence à la déclaration de classe dont le nom complet estN1.N2.A
.exemple de fin
Bien que chaque partie d’un type partiel (§15.2.7) soit déclarée dans le même espace de noms, les parties sont généralement écrites dans différentes déclarations d’espace de noms. Ainsi, différents extern_alias_directives et using_directivepeuvent être présents pour chaque partie. Lors de l’interprétation de noms simples (§12.8.4) dans une partie, seuls les extern_alias_directive s et les using_directivedes corps d’espace de noms et de l’unité de compilation englobant cette partie sont considérés. Cela peut entraîner le même identificateur ayant des significations différentes dans différentes parties.
Exemple :
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 } }
exemple de fin
L’utilisation d’alias peut nommer un type construit fermé, mais ne peut pas nommer une déclaration de type générique sans fournir d’arguments de type.
Exemple :
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 }
exemple de fin
14.5.3 Utilisation des directives d’espace de noms
Une using_namespace_directive importe les types contenus dans un espace de noms dans le corps de l’unité de compilation ou de l’espace de noms englobant immédiatement, ce qui permet à l’identificateur de chaque type d’être utilisé sans qualification.
using_namespace_directive
: 'using' namespace_name ';'
;
Dans les déclarations de membre d’une unité de compilation ou d’un corps d’espace de noms qui contient un using_namespace_directive, les types contenus dans l’espace de noms donné peuvent être référencés directement.
Exemple :
namespace N1.N2 { class A {} } namespace N3 { using N1.N2; class B : A {} }
Au-dessus, dans les déclarations de membre dans l’espace
N3
de noms, les membres de type sontN1.N2
directement disponibles, et par conséquent, la classeN3.B
dérive de la classeN1.N2.A
.exemple de fin
Une 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.
Exemple : dans le code suivant
namespace N1.N2 { class A {} } namespace N3 { using N1; class B : N2.A {} // Error, N2 unknown }
l’using_namespace_directive importe les types contenus dans
N1
, mais pas les espaces de noms imbriqués dansN1
. Par conséquent, la référence àN2.A
la déclaration des résultats d’une erreur au moment deB
la compilation, car aucun membre nomméN2
n’est dans l’étendue.exemple de fin
Contrairement à un using_alias_directive, un using_namespace_directive peut importer des types dont les identificateurs sont déjà définis dans l’unité de compilation englobante ou le corps de l’espace de noms. En effet, les noms importés par un using_namespace_directive sont masqués par des membres nommés de la même façon dans l’unité de compilation englobante ou le corps de l’espace de noms.
Exemple :
namespace N1.N2 { class A {} class B {} } namespace N3 { using N1.N2; class A {} }
Ici, dans les déclarations de membre dans l’espace
N3
de noms,A
fait référence auN3.A
lieu deN1.N2.A
.exemple de fin
Étant donné que les noms peuvent être ambigus lorsque plusieurs espaces de noms importés introduisent le même nom de type, une using_alias_directive est utile pour lever l’ambiguïté de la référence.
Exemple : dans le code suivant
namespace N1 { class A {} } namespace N2 { class A {} } namespace N3 { using N1; using N2; class B : A {} // Error, A is ambiguous }
les deux
N1
etN2
contiennent un membreA
, et parce queN3
les importations à la fois, leA
référencement estN3
une erreur au moment de la compilation. Dans cette situation, le conflit peut être résolu soit par la qualification des références àA
, soit en introduisant une using_alias_directive qui choisit un particulierA
. Par exemple :namespace N3 { using N1; using N2; using A = N1.A; class B : A {} // A means N1.A }
exemple de fin
En outre, lorsque plusieurs espaces de noms ou types importés par using_namespace_directives ou using_static_directives dans le même corps d’unité de compilation ou d’espace de noms 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.
Exemple :
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
contient un membreA
de type etC
contient un champA
statique, et parce queN2
les importations à la fois, leA
référencement en tant que simple_name est ambigu et une erreur au moment de la compilation.exemple de fin
Comme un using_alias_directive, un using_namespace_directive ne contribue pas aux nouveaux membres à l’espace de déclaration sous-jacent de l’unité de compilation ou de l’espace de noms, mais affecte uniquement l’unité de compilation ou le corps de l’espace de noms dans lequel il apparaît.
La namespace_name référencée par un using_namespace_directive est résolue de la même façon que la namespace_or_type_name référencée par un using_alias_directive. Par conséquent, les using_namespace_directivedans le même corps d’unité de compilation ou d’espace de noms n’affectent pas les uns les autres et peuvent être écrits dans n’importe quel ordre.
14.5.4 Utilisation de directives statiques
Une using_static_directive importe les types imbriqués et les membres statiques contenus directement dans une déclaration de type dans le corps de l’unité de compilation ou de l’espace de noms qui entoure immédiatement l’identificateur de chaque membre et type à utiliser sans qualification.
using_static_directive
: 'using' 'static' type_name ';'
;
Dans les déclarations de membre d’une unité de compilation ou d’un corps d’espace de noms qui contient un 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.
Exemple :
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(); } } }
Dans le code précédent, dans les déclarations de membre dans l’espace
N2
de noms, les membres statiques et les types imbriqués deN1.A
sont directement disponibles, et ainsi la méthodeN
est en mesure de référencer à la fois les membres etM
lesB
membres deN1.A
.exemple de fin
Une using_static_directive n’importe pas spécifiquement les méthodes d’extension directement en tant que méthodes statiques, mais les rend disponibles pour l’appel de méthode d’extension (§12.8.9.3).
Exemple :
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 } } }
la using_static_directive importe la méthode
M
d’extension contenue dansN1.A
, mais uniquement en tant que méthode d’extension. Par conséquent, la première référence auM
corps des résultats d’une erreur au moment deB.N
la compilation, car aucun membre nomméM
n’est dans l’étendue.exemple de fin
Une 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.
Exemple :
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 } } }
la using_static_directive importe la méthode
M2
contenue dansN1.B
, mais n’importe pas la méthodeM
contenue dansN1.A
. Par conséquent, la référence auM
corps des résultats d’une erreur au moment deC.N
la compilation, car aucun membre nomméM
n’est dans l’étendue. Les développeurs doivent ajouter une deuxièmeusing static
directive pour spécifier que les méthodes dansN1.A
devront également être importées.exemple de fin
Les ambiguïtés entre plusieurs using_namespace_directives et using_static_directives sont abordées dans le §14.5.3.
14.6 Déclarations de membre d’espace de noms
Un namespace_member_declaration est un namespace_declaration (§14.3) ou un type_declaration (§14.7).
namespace_member_declaration
: namespace_declaration
| type_declaration
;
Une unité de compilation ou un corps d’espace de noms peut contenir des namespace_member_declaration, et ces déclarations contribuent aux nouveaux membres à l’espace de déclaration sous-jacent de l’unité de compilation ou du corps de l’espace de noms contenant.
14.7 Déclarations de type
Un type_declaration est un class_declaration (§15.2), un struct_declaration (§16.2), un interface_declaration (§18.2), un enum_declaration (§19.2) ou un delegate_declaration (§20.2).
type_declaration
: class_declaration
| struct_declaration
| interface_declaration
| enum_declaration
| delegate_declaration
;
Une type_declaration peut se produire en tant que déclaration de niveau supérieur dans une unité de compilation ou en tant que déclaration membre dans un espace de noms, une classe ou un struct.
Lorsqu’une déclaration de type pour un type T
se produit en tant que déclaration de niveau supérieur dans une unité de compilation, le nom complet (§7.8.2) de la déclaration de type est identique au nom non qualifié de la déclaration (§7.8.2). Lorsqu’une déclaration de type pour un type T
se produit dans une déclaration d’espace de noms, de classe ou de struct, le nom complet (§7.8.3) de la déclaration S.N
de type, où S
est le nom complet de l’espace de noms, de la classe ou de la déclaration de struct contenant, et N
est le nom non qualifié de la déclaration.
Un type déclaré dans une classe ou un struct est appelé type imbriqué (§15.3.9).
Les modificateurs d’accès autorisés et l’accès par défaut pour une déclaration de type dépendent du contexte dans lequel la déclaration a lieu (§7.5.2) :
- Les types déclarés dans les unités de compilation ou les espaces de noms peuvent avoir
public
ouinternal
accéder. La valeur par défaut est l’accèsinternal
. - Les types déclarés dans les classes peuvent avoir
public
, ,protected internal
protected
,private protected
,internal
ouprivate
accéder. La valeur par défaut est l’accèsprivate
. - Les types déclarés dans les structs peuvent avoir
public
,internal
ouprivate
accéder. La valeur par défaut est l’accèsprivate
.
14.8 Membre d’alias qualifié
14.8.1 Général
Le qualificateur ::
d’alias d’espace de noms permet de garantir que les recherches de noms de type ne sont pas affectées par l’introduction de nouveaux types et membres. Le qualificateur d’alias d’espace de noms apparaît toujours entre deux identificateurs appelés identificateurs de gauche et de droite. Contrairement au qualificateur normal .
, l’identificateur de gauche du ::
qualificateur est recherché uniquement comme un extern ou en utilisant un alias.
Un qualified_alias_member fournit un accès explicite à l’espace de noms global et à l’extern ou à l’utilisation d’alias potentiellement masqués par d’autres entités.
qualified_alias_member
: identifier '::' identifier type_argument_list?
;
Un qualified_alias_member peut être utilisé comme namespace_or_type_name (§7.8) ou comme opérande gauche dans un member_access (§12.8.7).
Un qualified_alias_member se compose de deux identificateurs, appelés identificateurs de gauche et de droite, séparés par le ::
jeton et éventuellement suivis d’un type_argument_list. Lorsque l’identificateur de gauche est global, l’espace de noms global est recherché pour l’identificateur de droite. Pour tout autre identificateur de gauche, cet identificateur est recherché sous la forme d’un extern ou d’un alias (§14.4 et §14.5.2). Une erreur au moment de la compilation se produit s’il n’existe pas d’alias de ce type ou si l’alias fait référence à un type. Si l’alias fait référence à un espace de noms, cet espace de noms est recherché pour l’identificateur de droite.
Un qualified_alias_member a l’une des deux formes suivantes :
N::I<A₁, ..., Aₑ>
, oùN
etI
représentent des identificateurs, et<A₁, ..., Aₑ>
est une liste d’arguments de type. (e
est toujours au moins un.)N::I
, oùN
etI
représentent des identificateurs. (Dans ce cas,e
est considéré comme égal à zéro.)
À l’aide de cette notation, la signification d’une qualified_alias_member est déterminée comme suit :
- S’il
N
s’agit de l’identificateurglobal
, l’espace de noms global est recherché :I
- Si l’espace de noms global contient un espace de noms nommé
I
ete
est égal à zéro, la qualified_alias_member fait référence à cet espace de noms. - Sinon, si l’espace de noms global contient un type non générique nommé
I
ete
est égal à zéro, le qualified_alias_member fait référence à ce type. - Sinon, si l’espace de noms global contient un type nommé
I
qui ae
des paramètres de type, l’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.
- Si l’espace de noms global contient un espace de noms nommé
- Sinon, à partir de la déclaration d’espace de noms (§14.3) contenant immédiatement la 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 l’unité de déclaration ou de compilation d’espace de noms contient un using_alias_directive qui associe N à un type, le qualified_alias_member n’est pas défini et une erreur au moment de la compilation se produit.
- Sinon, si la déclaration d’espace de noms ou l’unité de compilation contient une extern_alias_directive ou using_alias_directive qui s’associe
N
à un espace de noms, puis :- Si l’espace de noms associé à
N
un espace de noms contient un espace de noms nomméI
ete
est égal à zéro, la 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
ete
est égal à zéro, la qualified_alias_member fait référence à ce type. - Sinon, si l’espace de noms associé à
N
contient un type nomméI
qui ae
des paramètres de type, l’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.
- Si l’espace de noms associé à
- Sinon, le qualified_alias_member n’est pas défini et une erreur au moment de la compilation se produit.
Exemple : Dans le code :
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; } }
la classe
A
est référencée avecglobal::A
et le typeSystem.Net.Sockets.Socket
est référencé avecS::Socket
. L’utilisationA.x
etS.Socket
à la place aurait provoqué des erreurs au moment de la compilation, carA
ellesS
auraient été résolues sur les paramètres.exemple de fin
Remarque : L’identificateur
global
a une signification particulière uniquement lorsqu’il est utilisé comme identificateur de gauche d’un qualified_alias_name. Ce n’est pas un mot clé et il n’est pas lui-même un alias ; il s’agit d’un mot clé contextuel (§6.4.4). Dans le code :class A { } class C { global.A x; // Error: global is not defined global::A y; // Valid: References A in the global namespace }
l’utilisation
global.A
provoque une erreur au moment de la compilation, car il n’existe aucune entité nomméeglobal
dans l’étendue. Si une entité nommée global était dans l’étendue,global
elleglobal.A
aurait été résolue sur cette entité.L’utilisation
global
comme identificateur de gauche d’un qualified_alias_member provoque toujours une recherche dans l’espaceglobal
de noms, même s’il existe un alias utilisant nomméglobal
. Dans le code :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
résoutMyGlobalTypes.A
etglobal::A
résout la classeA
dans l’espace de noms global.Note de fin
14.8.2 Unicité des alias
Chaque unité de compilation et corps de l’espace de noms possède un espace de déclaration distinct pour les alias extern et l’utilisation d’alias. Ainsi, alors que le nom d’un alias extern ou d’un alias d’utilisation doit être unique dans l’ensemble d’alias externs et en utilisant des alias déclarés dans le corps de l’unité de compilation ou de l’espace de noms immédiatement contenant, un alias est autorisé à avoir le même nom qu’un type ou un espace de noms tant qu’il est utilisé uniquement avec le ::
qualificateur.
Exemple : Dans les éléments suivants :
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 } }
le nom
A
a deux significations possibles dans le deuxième corps de l’espace de noms, car la classeA
et l’aliasA
using sont dans l’étendue. Pour cette raison, l’utilisation du nomA.Stream
qualifié est ambiguë et provoque une erreur au moment deA
la compilation. Toutefois, l’utilisation::
duA
qualificateur n’est pas une erreur, carA
elle n’est recherchée qu’en tant qu’alias d’espace de noms.exemple de fin
ECMA C# draft specification