14 namnområden
14.1 Allmänt
C#-program ordnas med hjälp av namnområden. Namnrymder används både som ett "internt" organisationssystem för ett program och som ett "externt" organisationssystem – ett sätt att presentera programelement som exponeras för andra program.
Användning av direktiv (§14.5) tillhandahålls för att underlätta användningen av namnområden.
14.2 Kompileringsenheter
En compilation_unit består av noll eller fler extern_alias_directiveföljt av noll eller fler using_directiveföljt av noll eller en global_attributes följt av noll eller fler namespace_member_declarations. Compilation_unit definierar den övergripande strukturen för indata.
compilation_unit
: extern_alias_directive* using_directive* global_attributes?
namespace_member_declaration*
;
Ett C#-program består av en eller flera kompileringsenheter. När ett C#-program kompileras bearbetas alla kompileringsenheter tillsammans. Kompileringsenheter kan därför vara beroende av varandra, möjligen på ett cirkulärt sätt.
Extern_alias_directive för en kompileringsenhet påverkar using_directives, global_attributes och namespace_member_declarationi den kompileringsenheten, men har ingen effekt på andra kompileringsenheter.
Using_directive för en kompileringsenhet påverkar global_attributes och namespace_member_declarationför den kompileringsenheten, men påverkar inte andra kompileringsenheter.
Den global_attributes (§22.3) av en kompileringsenhet tillåter specifikation av attribut för målsammansättningen och modulen. Sammansättningar och moduler fungerar som fysiska containrar för typer. En sammansättning kan bestå av flera fysiskt separata moduler.
De namespace_member_declarationför varje kompileringsenhet i ett program bidrar med medlemmar till ett enda deklarationsutrymme som kallas globalt namnområde.
Exempel:
// File A.cs: class A {} // File B.cs: class B {}
De två kompileringsenheterna bidrar till det enskilda globala namnområdet, i det här fallet deklarerar de två klasserna med de fullständigt kvalificerade namnen
A
ochB
. Eftersom de två kompileringsenheterna bidrar till samma deklarationsutrymme skulle det ha varit ett fel om var och en innehöll en deklaration av en medlem med samma namn.slutexempel
14.3 Namnområdesdeklarationer
En namespace_declaration består av nyckelordets namnområde följt av ett namnområdesnamn och en brödtext, eventuellt följt av ett semikolon.
namespace_declaration
: 'namespace' qualified_identifier namespace_body ';'?
;
qualified_identifier
: identifier ('.' identifier)*
;
namespace_body
: '{' extern_alias_directive* using_directive*
namespace_member_declaration* '}'
;
En namespace_declaration kan inträffa som en deklaration på toppnivå i en compilation_unit eller som en medlemsdeklaration inom en annan namespace_declaration. När en namespace_declaration inträffar som en toppnivådeklaration i en compilation_unit blir namnområdet medlem i det globala namnområdet. När en namespace_declaration inträffar inom en annan namespace_declaration blir det inre namnområdet medlem i det yttre namnområdet. I båda fallen ska namnet på ett namnområde vara unikt inom det innehållande namnområdet.
Namnområden är implicita public
och deklarationen av ett namnområde kan inte innehålla några åtkomstmodifierare.
Inom en namespace_body importerar den valfria using_directivenamnen på andra namnområden, typer och medlemmar, så att de kan refereras direkt i stället för via kvalificerade namn. Den valfria namespace_member_declarationbidrar medlemmar till namnområdets deklarationsutrymme. Observera att alla using_directiveska visas före eventuella medlemsdeklarationer.
Qualified_identifier för en namespace_declaration kan vara en enda identifierare eller en sekvens med identifierare avgränsade med ".
" token. Det senare formuläret tillåter ett program att definiera ett kapslat namnområde utan att lexikalt kapsla flera namnområdesdeklarationer.
Exempel:
namespace N1.N2 { class A {} class B {} }
är semantiskt likvärdigt med
namespace N1 { namespace N2 { class A {} class B {} } }
slutexempel
Namnområden är öppna och två namnområdesdeklarationer med samma fullständigt kvalificerade namn (§7.8.2) bidrar till samma deklarationsutrymme (§7.3).
Exempel: I följande kod
namespace N1.N2 { class A {} } namespace N1.N2 { class B {} }
de två namnområdesdeklarationerna ovan bidrar till samma deklarationsutrymme, i det här fallet deklarera två klasser med de fullständigt kvalificerade namnen
N1.N2.A
ochN1.N2.B
. Eftersom de två deklarationerna bidrar till samma deklarationsutrymme skulle det ha varit ett fel om var och en innehöll en deklaration av en medlem med samma namn.slutexempel
14.4 Externa aliasdirektiv
En extern_alias_directive introducerar en identifierare som fungerar som ett alias för ett namnområde. Specifikationen för det aliaserade namnområdet är externt för programmets källkod och gäller även för kapslade namnområden i det aliaserade namnområdet.
extern_alias_directive
: 'extern' 'alias' identifier ';'
;
Omfånget för en extern_alias_directive sträcker sig över using_directives, global_attributes och namespace_member_declarationav dess omedelbart innehållande compilation_unit eller namespace_body.
I en kompileringsenhet eller namnområdestext som innehåller en extern_alias_directive kan identifieraren som introducerades av extern_alias_directive användas för att referera till det aliaserade namnområdet. Det är ett kompileringsfel för att identifieraren ska vara ordet global
.
Aliaset som introduceras av en extern_alias_directive liknar det alias som introducerades av en using_alias_directive. Mer detaljerad information om extern_alias_directives och using_alias_directives finns i §14.5.2.
alias
är ett kontextuellt nyckelord (§6.4.4) och har endast särskild betydelse när det omedelbart följer nyckelordet extern
i en extern_alias_directive.
Ett fel uppstår om ett program deklarerar ett externt alias som ingen extern definition har angetts för.
Exempel: Följande program deklarerar och använder två externa alias och
X
, som var ochY
en representerar roten i en distinkt namnområdeshierarki:extern alias X; extern alias Y; class Test { X::N.A a; X::N.B b1; Y::N.B b2; Y::N.C c; }
Programmet deklarerar förekomsten av externa alias
X
ochY
, men de faktiska definitionerna av aliasen är externa för programmet. De identiskt namngivnaN.B
klasserna kan nu refereras till somX.N.B
ochY.N.B
, eller, med hjälp av namnområdets aliaskvalificerare,X::N.B
ochY::N.B
. slutexempel
14.5 Användning av direktiv
14.5.1 Allmänt
Med hjälp av direktiv underlättas användningen av namnområden och typer som definierats i andra namnområden. Användning av direktiv påverkar namnmatchningsprocessen för namespace_or_type_names (§7.8) och simple_name(§12.8.4), men till skillnad från deklarationer bidrar using_directiveinte nya medlemmar till de underliggande deklarationsutrymmena i kompileringsenheterna eller namnrymderna inom vilka de används.
using_directive
: using_alias_directive
| using_namespace_directive
| using_static_directive
;
En using_alias_directive (§14.5.2) introducerar ett alias för ett namnområde eller en typ.
En using_namespace_directive (§14.5.3) importerar typmedlemmarna i ett namnområde.
En using_static_directive (§14.5.4) importerar kapslade typer och statiska medlemmar av en typ.
Omfånget för en using_directive sträcker sig över namespace_member_declarations av dess omedelbart innehållande kompileringsenhet eller namnområdestext. Omfånget för en using_directive innehåller inte dess peer-using_directive s. Därför påverkar peer-using_directive inte varandra, och ordningen i vilken de skrivs är obetydlig. Omfånget för en extern_alias_directive innehåller däremot de using_directivesom definierats i samma kompileringsenhet eller namnområdestext.
14.5.2 Använda aliasdirektiv
En using_alias_directive introducerar en identifierare som fungerar som ett alias för ett namnområde eller en typ i den omedelbart omslutande kompileringsenheten eller namnområdestexten.
using_alias_directive
: 'using' identifier '=' namespace_or_type_name ';'
;
I globala attribut och medlemsdeklarationer i en kompileringsenhet eller namnområdestext som innehåller en using_alias_directive kan identifieraren som introducerades av using_alias_directive användas för att referera till det angivna namnområdet eller typen.
Exempel:
namespace N1.N2 { class A {} } namespace N3 { using A = N1.N2.A; class B: A {} }
Ovan, inom medlemsdeklarationer i namnområdet,
A
är ett alias förN1.N2.A
, och därför härleds klassenN3.B
från klassenN1.N2.A
.N3
Samma effekt kan erhållas genom att skapa ett aliasR
förN1.N2
och sedan referera tillR.A
:namespace N3 { using R = N1.N2; class B : R.A {} }
slutexempel
Inom användning av direktiv, globala attribut och medlemsdeklarationer i en kompileringsenhet eller namnområdestext som innehåller en extern_alias_directive kan identifieraren som introducerades av extern_alias_directive användas för att referera till det associerade namnområdet.
Exempel: Till exempel:
namespace N1 { extern alias N2; class B : N2::A {} }
Ovan, inom medlemsdeklarationer i
N1
namnområdet,N2
är ett alias för ett namnområde vars definition är extern mot programmets källkod. KlassenN1.B
härleds från klassenN2.A
. Samma effekt kan erhållas genom att skapa ett aliasA
förN2.A
och sedan referera tillA
:namespace N1 { extern alias N2; using A = N2::A; class B : A {} }
slutexempel
Ett extern_alias_directive eller using_alias_directive gör ett alias tillgängligt i en viss kompileringsenhet eller namnområdestext, men det bidrar inte med några nya medlemmar till det underliggande deklarationsutrymmet. Med andra ord är ett aliasdirektiv inte transitivt, utan påverkar snarare bara kompileringsenheten eller namnområdestexten där det inträffar.
Exempel: I följande kod
namespace N3 { extern alias R1; using R2 = N1.N2; } namespace N3 { class B : R1::A, R2.I {} // Error, R1 and R2 unknown }
omfången för de aliasdirektiv som inför
R1
ochR2
endast omfattar medlemsdeklarationer i namnområdestexten där de finns, såR1
ochR2
är okända i den andra namnområdesdeklarationen. Om du placerar aliasdirektiven i den innehållande kompileringsenheten blir aliaset dock tillgängligt i båda namnområdesdeklarationerna:extern alias R1; using R2 = N1.N2; namespace N3 { class B : R1::A, R2.I {} } namespace N3 { class C : R1::A, R2.I {} }
slutexempel
Varje extern_alias_directive eller using_alias_directive i en compilation_unit eller namespace_body bidrar med ett namn till aliasdeklarationsutrymmet (§7.3) för den omedelbart omslutande compilation_unit eller namespace_body. Aliasdirektivets identifierare ska vara unik inom motsvarande aliasdeklarationsutrymme. Aliasidentifieraren behöver inte vara unik inom det globala deklarationsutrymmet eller deklarationsutrymmet för motsvarande namnområde.
Exempel:
extern alias X; extern alias Y; using X = N1.N2; // Error: alias X already exists class Y {} // Ok
Det använda aliaset med namnet
X
orsakar ett fel eftersom det redan finns ett alias med namnetX
i samma kompileringsenhet. Klassen med namnetY
står inte i konflikt med det externa aliaset med namnetY
eftersom dessa namn läggs till i distinkta deklarationsutrymmen. Det förra läggs till i det globala deklarationsutrymmet och det senare läggs till i aliasdeklarationsutrymmet för den här kompileringsenheten.När ett aliasnamn matchar namnet på en medlem i ett namnområde ska användningen av något av dessa vara lämpligt kvalificerat:
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 }
I den andra namnområdestexten för
N3
resulterar okvalificerad användning avB
ett fel, eftersomN3
innehåller en medlem med namnetB
och namnområdestexten som också deklarerar ett alias med namnetB
; på samma sätt förA
. KlassenN3.B
kan refereras till somN3.B
ellerglobal::N3.B
. AliasetA
kan användas i en kvalificerad aliasmedlem (§14.8), till exempelA::B
. AliasetB
är i princip värdelöst. Det kan inte användas i en qualified_alias_member eftersom endast namnområdesalias kan användas i en qualified_alias_member ochB
alias en typ.slutexempel
Precis som vanliga medlemmar döljs namn som introduceras av alias_directives av medlemmar med liknande namn i kapslade omfång.
Exempel: I följande kod
using R = N1.N2; namespace N3 { class R {} class B: R.A {} // Error, R has no member A }
referensen till
R.A
i deklarationen avB
orsakar ett kompileringsfel eftersomR
refererar tillN3.R
, inteN1.N2
.slutexempel
Den ordning i vilken extern_alias_directiveskrivs har ingen betydelse. På samma sätt har den ordning i vilken using_alias_directives skrivs ingen betydelse, men alla using_alias_directives ska komma efter alla extern_alias_directives i samma kompileringsenhet eller namnområdestext. Upplösningen av namespace_or_type_name som refereras av en using_alias_directive påverkas inte av själva using_alias_directive eller av andra using_directivei den omedelbart innehållande kompileringsenheten eller namnområdestexten, men kan påverkas av extern_alias_directivei den omedelbart innehållande kompileringsenheten eller namnområdestexten. Med andra ord löses namespace_or_type_name av en using_alias_directive som om den omedelbart innehållande kompileringsenheten eller namnområdestexten inte hade några using_directivemen har rätt uppsättning extern_alias_directives.
Exempel: I följande kod
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 }
den senaste using_alias_directive resulterar i ett kompileringsfel eftersom det inte påverkas av föregående using_alias_directive. Den första using_alias_directive resulterar inte i ett fel eftersom omfånget för det externa aliaset X innehåller using_alias_directive.
slutexempel
En using_alias_directive kan skapa ett alias för valfritt namnområde eller typ, inklusive namnområdet där det visas och alla namnområden eller typer som är kapslade i namnområdet.
Åtkomst till ett namnområde eller en typ via ett alias ger exakt samma resultat som åtkomst till namnområdet eller typ via dess deklarerade namn.
Exempel: Givet
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 } }
namnen
N1.N2.A
, , ochR2.A
är likvärdiga och alla refererar till klassdeklarationen vars fullständigt kvalificerade namn ärN1.N2.A
R1.N2.A
.slutexempel
Även om varje del av en partiell typ (§15.2.7) deklareras inom samma namnområde, skrivs delarna vanligtvis inom olika namnområdesdeklarationer. Därför kan olika extern_alias_directives och using_directives finnas för varje del. Vid tolkning av enkla namn (§12.8.4) inom en del anses endast extern_alias_directive s och using_directives i namnområdets organ och kompileringsenhet som omger den delen. Detta kan leda till att samma identifierare har olika betydelser i olika delar.
Exempel:
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 } }
slutexempel
Om du använder alias kan du namnge en sluten konstruktionstyp, men det går inte att namnge en obundet allmän typdeklaration utan att ange typargument.
Exempel:
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 }
slutexempel
14.5.3 Använda namnområdesdirektiv
En using_namespace_directive importerar de typer som finns i ett namnområde till den omedelbart omslutande kompileringsenheten eller namnområdestexten, vilket gör att identifieraren för varje typ kan användas utan kvalificering.
using_namespace_directive
: 'using' namespace_name ';'
;
I medlemsdeklarationer i en kompileringsenhet eller namnområdestext som innehåller en using_namespace_directive kan de typer som finns i det angivna namnområdet refereras direkt.
Exempel:
namespace N1.N2 { class A {} } namespace N3 { using N1.N2; class B : A {} }
Ovan, inom medlemsdeklarationer i
N3
namnområdet, är typen medlemmar avN1.N2
direkt tillgängliga, och därmed härleds klassenN3.B
från klassenN1.N2.A
.slutexempel
En using_namespace_directive importerar de typer som finns i det angivna namnområdet, men importerar inte kapslade namnområden.
Exempel: I följande kod
namespace N1.N2 { class A {} } namespace N3 { using N1; class B : N2.A {} // Error, N2 unknown }
using_namespace_directive importerar typerna i
N1
, men inte de namnområden som är kapslade iN1
. Referensen tillN2.A
i deklarationen resulterarB
alltså i ett kompileringsfel eftersom inga medlemmar med namnetN2
finns i omfånget.slutexempel
Till skillnad från en using_alias_directive kan en using_namespace_directive importera typer vars identifierare redan har definierats i den omslutande kompileringsenheten eller namnområdestexten. I själva verket döljs namn som importeras av en using_namespace_directive av medlemmar med liknande namn i den omslutande kompileringsenheten eller namnområdestexten.
Exempel:
namespace N1.N2 { class A {} class B {} } namespace N3 { using N1.N2; class A {} }
Här refererar i medlemsdeklarationer i
N3
namnområdetA
till i ställetN1.N2.A
förN3.A
.slutexempel
Eftersom namn kan vara tvetydiga när fler än ett importerat namnområde introducerar samma typnamn är en using_alias_directive användbar för att skilja referensen åt.
Exempel: I följande kod
namespace N1 { class A {} } namespace N2 { class A {} } namespace N3 { using N1; using N2; class B : A {} // Error, A is ambiguous }
både
N1
ochN2
innehåller en medlemA
, och eftersomN3
importer av båda är hänvisningarA
iN3
ett kompileringsfel. I den här situationen kan konflikten lösas antingen genom kvalificering av referenser till , eller genom attA
införa en using_alias_directive som väljer en vissA
. Till exempel:namespace N3 { using N1; using N2; using A = N1.A; class B : A {} // A means N1.A }
slutexempel
Om fler än ett namnområde eller en typ som importerats av using_namespace_directives eller using_static_directives i samma kompileringsenhet eller namnområdestext innehåller typer eller medlemmar med samma namn, betraktas referenser till det namnet som en simple_name tvetydiga.
Exempel:
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
innehåller en typmedlemA
ochC
innehåller ett statiskt fältA
, och eftersomN2
importerar båda, är det tvetydigt att referera tillA
som en simple_name och ett kompileringsfel.slutexempel
Precis som en using_alias_directive bidrar inte en using_namespace_directive några nya medlemmar till det underliggande deklarationsutrymmet i kompileringsenheten eller namnområdet, utan påverkar i stället bara kompileringsenheten eller namnområdestexten där den visas.
Den namespace_name som refereras av en using_namespace_directive löses på samma sätt som namespace_or_type_name som refereras av en using_alias_directive. Därför påverkar using_namespace_directivei samma kompileringsenhet eller namnområdestext inte varandra och kan skrivas i valfri ordning.
14.5.4 Användning av statiska direktiv
En using_static_directive importerar kapslade typer och statiska medlemmar som finns direkt i en typdeklaration till den omedelbart omslutande kompileringsenheten eller namnområdestexten, vilket gör det möjligt att använda identifieraren för varje medlem och typ utan kvalificering.
using_static_directive
: 'using' 'static' type_name ';'
;
I medlemsdeklarationer i en kompileringsenhet eller namnområdestext som innehåller en using_static_directive kan tillgängliga kapslade typer och statiska medlemmar (förutom tilläggsmetoder) som finns direkt i deklarationen av den angivna typen refereras direkt.
Exempel:
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(); } } }
I föregående kod, inom medlemsdeklarationer i
N2
namnområdet, är de statiska medlemmarna och kapslade typerna avN1.A
direkt tillgängliga, och metodenN
kan därför referera till bådeB
ochM
medlemmar iN1.A
.slutexempel
En using_static_directive importerar inte tilläggsmetoder direkt som statiska metoder, utan gör dem tillgängliga för anrop av tilläggsmetod (§12.8.9.3).
Exempel:
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 } } }
using_static_directive importerar tilläggsmetoden
M
iN1.A
, men bara som en tilläggsmetod. Därför resulterar den första referensen iM
brödtextenB.N
i ett kompileringsfel eftersom inga medlemmar med namnetM
finns i omfånget.slutexempel
En using_static_directive importerar endast medlemmar och typer som deklarerats direkt i den angivna typen, inte medlemmar och typer som deklarerats i basklasser.
Exempel:
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 } } }
using_static_directive importerar metoden
M2
iN1.B
, men importerar inte metodenM
iN1.A
. Referensen tillM
i brödtextenC.N
i resulterar därför i ett kompileringsfel eftersom inga medlemmar med namnetM
finns i omfånget. Utvecklare måste lägga till ett andrausing static
direktiv för att ange att metoderna iN1.A
också ska importeras.slutexempel
Tvetydigheter mellan flera using_namespace_directives och using_static_directives diskuteras i §14.5.3.
14.6 Medlemsdeklarationer för namnområde
En namespace_member_declaration är antingen en namespace_declaration (§14.3) eller en type_declaration (§14.7).
namespace_member_declaration
: namespace_declaration
| type_declaration
;
En kompileringsenhet eller en namnområdestext kan innehålla namespace_member_declarations, och sådana deklarationer bidrar med nya medlemmar till det underliggande deklarationsutrymmet för den innehållande kompileringsenheten eller namnområdestexten.
14.7 Typdeklarationer
En type_declaration är en class_declaration (§15.2), en struct_declaration (§16.2), en interface_declaration (§18.2), en enum_declaration (§19.2) eller en delegate_declaration (§20.2).
type_declaration
: class_declaration
| struct_declaration
| interface_declaration
| enum_declaration
| delegate_declaration
;
En type_declaration kan inträffa som en deklaration på den översta nivån i en kompileringsenhet eller som en medlemsdeklaration inom ett namnområde, en klass eller en struct.
När en typdeklaration för en typ T
inträffar som en toppnivådeklaration i en kompileringsenhet är det fullständigt kvalificerade namnet (§7.8.2) av typdeklarationen detsamma som det okvalificerade namnet på deklarationen (§7.8.2). När en typdeklaration för en typ T
inträffar inom ett namnområde, en klass eller en structdeklaration, är det fullständigt kvalificerade namnet (§7.8.3) av typdeklarationen S.N
, där S
är det fullständigt kvalificerade namnet på det innehållande namnområdet, klassen eller structdeklarationen, och N
är det okvalificerade namnet på deklarationen.
En typ som deklareras inom en klass eller struct kallas kapslad typ (§15.3.9).
De tillåtna åtkomstmodifierarna och standardåtkomsten för en typdeklaration beror på i vilket sammanhang deklarationen äger rum (§7.5.2):
- Typer som deklareras i kompileringsenheter eller namnområden kan ha
public
ellerinternal
komma åt. Standardvärdet ärinternal
åtkomst. - Typer som deklareras i klasser kan ha
public
,protected internal
,protected
,private protected
,internal
ellerprivate
åtkomst. Standardvärdet ärprivate
åtkomst. - Typer som deklareras i structs kan ha
public
,internal
ellerprivate
åtkomst. Standardvärdet ärprivate
åtkomst.
14.8 Kvalificerad aliasmedlem
14.8.1 Allmänt
Namnområdesaliaskvalificeraren ::
gör det möjligt att garantera att typnamnsökningar inte påverkas av introduktionen av nya typer och medlemmar. Namnområdesaliaskvalificeraren visas alltid mellan två identifierare som kallas för vänster- och högeridentifierare. Till skillnad från den vanliga .
kvalificeraren, letas den vänstra identifieraren för kvalificeringen ::
endast upp som extern eller med hjälp av alias.
Ett qualified_alias_member ger explicit åtkomst till det globala namnområdet och till externt eller med hjälp av alias som potentiellt döljs av andra entiteter.
qualified_alias_member
: identifier '::' identifier type_argument_list?
;
En qualified_alias_member kan användas som en namespace_or_type_name (§7.8) eller som vänster operande i en member_access (§12.8.7).
En qualified_alias_member består av två identifierare, så kallade vänster- och högeridentifierare, avgränsade med ::
token och eventuellt följt av en type_argument_list. När den vänstra identifieraren är global söks det globala namnområdet efter den högra identifieraren. För andra vänsteridentifierare söks identifieraren upp som extern eller med alias (§14.4 och §14.5.2). Ett kompileringsfel uppstår om det inte finns något sådant alias eller om aliaset refererar till en typ. Om aliaset refererar till ett namnområde söks namnområdet efter den högra identifieraren.
En qualified_alias_member har ett av två formulär:
N::I<A₁, ..., Aₑ>
, därN
ochI
representerar identifierare och<A₁, ..., Aₑ>
är en typargumentlista. (e
är alltid minst en.)N::I
, därN
ochI
representerar identifierare. (I det här fallete
anses vara noll.)
Med den här notationen bestäms innebörden av en qualified_alias_member på följande sätt:
- Om
N
är identifierarenglobal
söksI
det globala namnområdet efter :- Om det globala namnområdet innehåller ett namnområde med namnet
I
oche
är noll refererar qualified_alias_member till namnområdet. - Annars, om det globala namnområdet innehåller en icke-generisk typ med namnet
I
oche
är noll, refererar qualified_alias_member till den typen. - Annars, om det globala namnområdet innehåller en typ med namnet
I
som hare
typparametrar, refererar qualified_alias_member till den typen som skapats med de angivna typargumenten. - Annars är qualified_alias_member odefinierat och ett kompileringsfel inträffar.
- Om det globala namnområdet innehåller ett namnområde med namnet
- Annars, från och med namnområdesdeklarationen (§14.3) som omedelbart innehåller qualified_alias_member (om sådan finns), fortsätter med varje omslutande namnområdesdeklaration (om sådan finns) och slutar med kompileringsenheten som innehåller qualified_alias_member, utvärderas följande steg tills en entitet finns:
- Om namnområdesdeklarationen eller kompileringsenheten innehåller en using_alias_directive som associerar N med en typ är qualified_alias_member odefinierad och ett kompileringsfel inträffar.
- Om namnområdesdeklarationen eller kompileringsenheten annars innehåller en extern_alias_directive eller using_alias_directive som associeras
N
med ett namnområde:- Om namnområdet som är associerat med
N
innehåller ett namnområde med namnetI
oche
är noll refererar qualified_alias_member till namnområdet. - Annars, om namnområdet som är associerat med
N
innehåller en icke-generisk typ med namnetI
oche
är noll, refererar qualified_alias_member till den typen. - Annars, om namnområdet som är associerat med
N
innehåller en typ med namnetI
som hare
typparametrar, refererar qualified_alias_member till den typen som skapats med de angivna typargumenten. - Annars är qualified_alias_member odefinierat och ett kompileringsfel inträffar.
- Om namnområdet som är associerat med
- Annars är qualified_alias_member odefinierat och ett kompileringsfel inträffar.
Exempel: I koden:
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; } }
-klassen
A
refereras till ochglobal::A
typenSystem.Net.Sockets.Socket
refereras till medS::Socket
. Att användaA.x
ochS.Socket
i stället skulle ha orsakat kompileringsfel eftersomA
ochS
skulle ha matchat parametrarna.slutexempel
Obs! Identifieraren
global
har endast särskild betydelse när den används som vänsteridentifierare för en qualified_alias_name. Det är inte ett nyckelord och det är inte i sig ett alias. det är ett kontextuellt nyckelord (§6.4.4). I koden:class A { } class C { global.A x; // Error: global is not defined global::A y; // Valid: References A in the global namespace }
användning
global.A
orsakar ett kompileringsfel eftersom det inte finns någon entitet med namnetglobal
i omfånget. Om någon entitet med namnet global fanns i omfångetglobal
skulle inglobal.A
ha matchats till den entiteten.Att använda
global
som vänsteridentifierare för en qualified_alias_member alltid orsakar en sökning iglobal
namnområdet, även om det finns ett alias med namnetglobal
. I koden: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
löserMyGlobalTypes.A
till ochglobal::A
matchar klassenA
i det globala namnområdet.slutkommentar
14.8.2 Aliasens unika egenskaper
Varje kompileringsenhet och namnområdestext har ett separat deklarationsutrymme för externa alias och med hjälp av alias. Även om namnet på ett externt alias eller ett alias ska vara unikt inom uppsättningen externa alias och använda alias som deklareras i den omedelbart innehållande kompileringsenheten eller namnområdestexten, tillåts ett alias ha samma namn som en typ eller ett namnområde så länge det endast används med ::
kvalificeraren.
Exempel: I följande:
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 } }
namnet
A
har två möjliga betydelser i den andra namnområdestexten eftersom både klassenA
och det använda aliasetA
finns i omfånget. Därför är användningen avA
i det kvalificerade namnetA.Stream
tvetydig och orsakar ett kompileringsfel. Användning avA
med kvalificeraren::
är dock inte ett fel eftersomA
det endast är ett namnområdesalias.slutexempel
ECMA C# draft specification