14 naamruimten
14.1 Algemeen
C#-programma's zijn ingedeeld met behulp van naamruimten. Naamruimten worden zowel gebruikt als een 'intern' organisatiesysteem voor een programma en als een 'extern' organisatiesysteem, een manier om programma-elementen weer te geven die beschikbaar zijn voor andere programma's.
Gebruiksrichtlijnen (§14.5) worden verstrekt om het gebruik van naamruimten te vergemakkelijken.
14.2 Compilatie-eenheden
Een compilation_unit bestaat uit nul of meer extern_alias_directivegevolgd door nul of meer using_directivegevolgd door nul of één global_attributes gevolgd door nul of meer namespace_member_declarations. De compilation_unit definieert de algehele structuur van de invoer.
compilation_unit
: extern_alias_directive* using_directive* global_attributes?
namespace_member_declaration*
;
Een C#-programma bestaat uit een of meer compilatie-eenheden. Wanneer een C#-programma wordt gecompileerd, worden alle compilatie-eenheden samen verwerkt. Compilatie-eenheden kunnen dus afhankelijk zijn van elkaar, mogelijk op circulaire wijze.
De extern_alias_directivevan een compilatie-eenheid zijn van invloed op de using_directives, global_attributes en namespace_member_declarations van die compilatie-eenheid, maar hebben geen invloed op andere compilatie-eenheden.
De using_directivevan een compilatie-eenheid heeft invloed op de global_attributes en namespace_member_declarationvan die compilatie-eenheid, maar hebben geen invloed op andere compilatie-eenheden.
De global_attributes (§22.3) van een compilatie-eenheid staat de specificatie van kenmerken voor de doelassembly en module toe. Assembly's en modules fungeren als fysieke containers voor typen. Een assembly kan bestaan uit verschillende fysiek afzonderlijke modules.
De namespace_member_declarationvan elke compilatie-eenheid van een programma dragen leden bij aan één declaratieruimte genaamd de globale naamruimte.
Voorbeeld:
// File A.cs: class A {} // File B.cs: class B {}
De twee compilatie-eenheden dragen bij aan de enkele globale naamruimte, in dit geval het declareren van twee klassen met de volledig gekwalificeerde namen
A
enB
. Omdat de twee compilatie-eenheden bijdragen aan dezelfde declaratieruimte, zou het een fout zijn geweest als elk een declaratie van een lid met dezelfde naam bevatte.eindvoorbeeld
14.3 Naamruimtedeclaraties
Een namespace_declaration bestaat uit de sleutelwoordnaamruimte, gevolgd door een naamruimtenaam en hoofdtekst, eventueel gevolgd door een puntkomma.
namespace_declaration
: 'namespace' qualified_identifier namespace_body ';'?
;
qualified_identifier
: identifier ('.' identifier)*
;
namespace_body
: '{' extern_alias_directive* using_directive*
namespace_member_declaration* '}'
;
Een namespace_declaration kan optreden als een verklaring op het hoogste niveau in een compilation_unit of als liddeclaratie binnen een andere namespace_declaration. Wanneer een namespace_declaration plaatsvindt als een declaratie op het hoogste niveau in een compilation_unit, wordt de naamruimte lid van de globale naamruimte. Wanneer een namespace_declaration plaatsvindt binnen een andere namespace_declaration, wordt de binnennaamruimte lid van de buitenste naamruimte. In beide gevallen moet de naam van een naamruimte uniek zijn binnen de naamruimte die de naamruimte bevat.
Naamruimten zijn impliciet public
en de declaratie van een naamruimte kan geen toegangsmodifiers bevatten.
Binnen een namespace_body importeert de optionele using_directivede namen van andere naamruimten, typen en leden, zodat ze rechtstreeks kunnen worden verwezen in plaats van via gekwalificeerde namen. De optionele namespace_member_declarationdragen leden bij aan de declaratieruimte van de naamruimte. Houd er rekening mee dat alle using_directive'sworden weergegeven vóór eventuele lidverklaringen.
De qualified_identifier van een namespace_declaration kan één id of een reeks id's zijn, gescheiden door tokens.
. Met dit laatste formulier kan een programma een geneste naamruimte definiëren zonder lexiek verschillende naamruimtedeclaraties te nesten.
Voorbeeld:
namespace N1.N2 { class A {} class B {} }
semantisch gelijk is aan
namespace N1 { namespace N2 { class A {} class B {} } }
eindvoorbeeld
Naamruimten zijn open-ended en twee naamruimtedeclaraties met dezelfde volledig gekwalificeerde naam (§7.8.2) dragen bij aan dezelfde declaratieruimte (§7.3).
Voorbeeld: In de volgende code
namespace N1.N2 { class A {} } namespace N1.N2 { class B {} }
de twee bovenstaande naamruimtedeclaraties dragen bij aan dezelfde declaratieruimte, in dit geval het declareren van twee klassen met de volledig gekwalificeerde namen
N1.N2.A
enN1.N2.B
. Omdat de twee declaraties bijdragen aan dezelfde declaratieruimte, zou het een fout zijn geweest als elk een declaratie van een lid met dezelfde naam bevatte.eindvoorbeeld
14.4 Externe aliasrichtlijnen
Een extern_alias_directive introduceert een id die fungeert als een alias voor een naamruimte. De specificatie van de aliasnaamruimte is extern voor de broncode van het programma en is ook van toepassing op geneste naamruimten van de aliasnaamruimte.
extern_alias_directive
: 'extern' 'alias' identifier ';'
;
Het bereik van een extern_alias_directive strekt zich uit over de using_directives, global_attributes en namespace_member_declarations van de compilation_unit of namespace_body.
Binnen een compilatie-eenheid of naamruimtebody die een extern_alias_directive bevat, kan de id die door de extern_alias_directive wordt geïntroduceerd, worden gebruikt om te verwijzen naar de aliasnaamruimte. Het is een compilatietijdfout voor de id om het woord global
te zijn.
De alias die door een extern_alias_directive wordt geïntroduceerd, is vergelijkbaar met de alias die is geïntroduceerd door een using_alias_directive. Zie §14.5.2 voor meer gedetailleerde bespreking van extern_alias_directives en using_alias_directives.
alias
is een contextueel trefwoord (§6.4.4) en heeft alleen een speciale betekenis wanneer het direct volgt op het extern
trefwoord in een extern_alias_directive.
Er treedt een fout op als een programma een extern alias declareert waarvoor geen externe definitie is opgegeven.
Voorbeeld: Het volgende programma declareert en gebruikt twee externe aliassen en
X
Y
, die elk de hoofdmap van een afzonderlijke naamruimtehiërarchie vertegenwoordigen:extern alias X; extern alias Y; class Test { X::N.A a; X::N.B b1; Y::N.B b2; Y::N.C c; }
Het programma declareert het bestaan van de externe aliassen
X
enY
, maar de werkelijke definities van de aliassen zijn extern voor het programma. Naar de identieke benoemdeN.B
klassen kan nu worden verwezen alsX.N.B
enY.N.B
, of, met behulp van de aliaskwalificatie van de naamruimte,X::N.B
enY::N.B
. eindvoorbeeld
14.5 Met behulp van instructies
14.5.1 Algemeen
Het gebruik van instructies vergemakkelijkt het gebruik van naamruimten en typen die zijn gedefinieerd in andere naamruimten. Het gebruik van richtlijnen is van invloed op het naamomzettingsproces van namespace_or_type_name s (§7.8) en simple_names (§12.8.4), maar in tegenstelling tot declaraties dragen using_directivegeen nieuwe leden bij aan de onderliggende declaratieruimten van de compilatie-eenheden of naamruimten waarin ze worden gebruikt.
using_directive
: using_alias_directive
| using_namespace_directive
| using_static_directive
;
Een using_alias_directive (§14.5.2) introduceert een alias voor een naamruimte of type.
Een using_namespace_directive (§14.5.3) importeert het type leden van een naamruimte.
Een using_static_directive (§14.5.4) importeert de geneste typen en statische leden van een type.
Het bereik van een using_directive strekt zich uit over de namespace_member_declarations van het direct met de hoofdtekst van de compilatie-eenheid of naamruimte. Het bereik van een using_directive omvat niet specifiek de peer-using_directive s. Peer-using_directive's hebben dus geen invloed op elkaar en de volgorde waarin ze worden geschreven, is onbelangrijk. Het bereik van een extern_alias_directive bevat daarentegen de using_directivedie zijn gedefinieerd in dezelfde hoofdtekst van de compilatie-eenheid of naamruimte.
14.5.2 Met aliasrichtlijnen
Een using_alias_directive introduceert een id die fungeert als een alias voor een naamruimte of type binnen de direct ingesloten compilatie-eenheid of naamruimtetekst.
using_alias_directive
: 'using' identifier '=' namespace_or_type_name ';'
;
Binnen globale kenmerken en liddeclaraties in een compilatie-eenheid of naamruimtetekst die een using_alias_directive bevat, kan de id die door de using_alias_directive wordt geïntroduceerd, worden gebruikt om te verwijzen naar de opgegeven naamruimte of het opgegeven type.
Voorbeeld:
namespace N1.N2 { class A {} } namespace N3 { using A = N1.N2.A; class B: A {} }
Boven, binnen liddeclaraties in de
N3
naamruimte,A
is een alias voorN1.N2.A
, en dus klasseN3.B
afgeleid van klasseN1.N2.A
. Hetzelfde effect kan worden verkregen door een aliasR
te maken voorN1.N2
en vervolgens te verwijzen naarR.A
:namespace N3 { using R = N1.N2; class B : R.A {} }
eindvoorbeeld
Binnen het gebruik van instructies, globale kenmerken en liddeclaraties in een compilatie-eenheid of naamruimtetekst die een extern_alias_directive bevat, kan de id die door de extern_alias_directive wordt geïntroduceerd, worden gebruikt om te verwijzen naar de bijbehorende naamruimte.
Voorbeeld: bijvoorbeeld:
namespace N1 { extern alias N2; class B : N2::A {} }
Boven is binnen liddeclaraties in de
N1
naamruimteN2
een alias voor een naamruimte waarvan de definitie extern is voor de broncode van het programma. KlasseN1.B
is afgeleid van klasseN2.A
. Hetzelfde effect kan worden verkregen door een aliasA
te maken voorN2.A
en vervolgens te verwijzen naarA
:namespace N1 { extern alias N2; using A = N2::A; class B : A {} }
eindvoorbeeld
Een extern_alias_directive of using_alias_directive maakt een alias beschikbaar in een bepaalde hoofdtekst van een compilatie-eenheid of naamruimte, maar draagt geen nieuwe leden bij aan de onderliggende declaratieruimte. Met andere woorden, een aliasrichtlijn is niet transitief, maar is, in plaats daarvan, alleen van invloed op de hoofdtekst van de compilatie-eenheid of naamruimte waarin deze zich voordoet.
Voorbeeld: In de volgende code
namespace N3 { extern alias R1; using R2 = N1.N2; } namespace N3 { class B : R1::A, R2.I {} // Error, R1 and R2 unknown }
de bereiken van de aliasrichtlijnen die liddeclaraties introduceren
R1
enR2
alleen uitbreiden naar liddeclaraties in de naamruimtetekst waarin ze zijn opgenomen, dusR1
enR2
zijn onbekend in de declaratie van de tweede naamruimte. Als u de aliasrichtlijnen echter in de bijbehorende compilatie-eenheid plaatst, wordt de alias beschikbaar in beide naamruimtedeclaraties:extern alias R1; using R2 = N1.N2; namespace N3 { class B : R1::A, R2.I {} } namespace N3 { class C : R1::A, R2.I {} }
eindvoorbeeld
Elke extern_alias_directive of using_alias_directive in een compilation_unit of namespace_body draagt een naam bij aan de aliasdeclaratieruimte (§7.3) van het onmiddellijk insluiten van compilation_unit of namespace_body. De id van de aliasrichtlijn moet uniek zijn binnen de corresponderende aliasdeclaratieruimte. De alias-id hoeft niet uniek te zijn binnen de globale declaratieruimte of de declaratieruimte van de bijbehorende naamruimte.
Voorbeeld:
extern alias X; extern alias Y; using X = N1.N2; // Error: alias X already exists class Y {} // Ok
De using-alias met de naam
X
veroorzaakt een fout, omdat er al een alias is met de naamX
in dezelfde compilatie-eenheid. De klasse met de naamY
conflicteren niet met de externe alias,Y
omdat deze namen worden toegevoegd aan afzonderlijke declaratieruimten. De eerste wordt toegevoegd aan de algemene declaratieruimte en de laatste wordt toegevoegd aan de aliasdeclaratieruimte voor deze compilatie-eenheid.Wanneer een aliasnaam overeenkomt met de naam van een lid van een naamruimte, moet het gebruik van een van beide op de juiste wijze worden gekwalificeerd:
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 }
In de tweede naamruimtetekst voor
N3
, niet-gekwalificeerd gebruik vanB
resultaten in een fout, omdatN3
bevat een lid met de naamB
en de naamruimtebody die ook een alias met naamB
declareert ; eveneens voorA
. Naar de klasseN3.B
kan worden verwezen alsN3.B
ofglobal::N3.B
. De aliasA
kan worden gebruikt in een qualified-alias-member (§14.8), zoalsA::B
. De aliasB
is in wezen nutteloos. Het kan niet worden gebruikt in een qualified_alias_member omdat alleen naamruimtealiassen kunnen worden gebruikt in een qualified_alias_member enB
aliassen van een type.eindvoorbeeld
Net als gewone leden worden namen die door alias_directives worden geïntroduceerd, verborgen door vergelijkbare benoemde leden in geneste bereiken.
Voorbeeld: In de volgende code
using R = N1.N2; namespace N3 { class R {} class B: R.A {} // Error, R has no member A }
de verwijzing naar
R.A
in de declaratie vanB
oorzaken een compilatietijdfout omdatR
verwijst naarN3.R
, nietN1.N2
.eindvoorbeeld
De volgorde waarin extern_alias_directive szijn geschreven, heeft geen betekenis. Op dezelfde manier heeft de volgorde waarin using_alias_directives zijn geschreven geen significantie, maar alle using_alias_directives komen na alle extern_alias_directives in dezelfde hoofdtekst van de compilatie-eenheid of naamruimte. De oplossing van de namespace_or_type_name waarnaar wordt verwezen door een using_alias_directive wordt niet beïnvloed door de using_alias_directive zelf of door andere using_directives in de direct bevattende hoofdtekst van de compilatie-eenheid of naamruimte, maar kan worden beïnvloed door extern_alias_directives in de direct bevattende hoofdtekst van de compilatie-eenheid of naamruimte. Met andere woorden, de namespace_or_type_name van een using_alias_directive wordt opgelost alsof de hoofdtekst van de compilatie-eenheid of naamruimte geen using_directive shad, maar de juiste set extern_alias_directives heeft.
Voorbeeld: In de volgende code
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 }
de laatste using_alias_directive resulteert in een compilatietijdfout omdat deze niet wordt beïnvloed door de vorige using_alias_directive. De eerste using_alias_directive resulteert niet in een fout omdat het bereik van de externe alias X de using_alias_directive bevat.
eindvoorbeeld
Een using_alias_directive kan een alias maken voor elke naamruimte of elk type, inclusief de naamruimte waarin deze wordt weergegeven en elke naamruimte of typ genest in die naamruimte.
Het openen van een naamruimte of type via een alias levert precies hetzelfde resultaat op als het openen van die naamruimte of het typen via de gedeclareerde naam.
Voorbeeld: Gegeven
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 } }
de namen
N1.N2.A
,R1.N2.A
en zijn gelijkwaardig enR2.A
allemaal verwijzen naar de klassedeclaratie waarvan de volledig gekwalificeerde naam isN1.N2.A
.eindvoorbeeld
Hoewel elk deel van een gedeeltelijk type (§15.2.7) binnen dezelfde naamruimte wordt gedeclareerd, worden de onderdelen meestal binnen verschillende naamruimtedeclaraties geschreven. Daarom kunnen verschillende extern_alias_directiveen using_directives aanwezig zijn voor elk onderdeel. Bij het interpreteren van eenvoudige namen (§12.8.4) binnen één deel, worden alleen de extern_alias_directives en using_directivevan de naamruimteteksten en compilatie-eenheden die dat deel insluiten beschouwd. Dit kan ertoe leiden dat dezelfde id verschillende betekenissen in verschillende delen heeft.
Voorbeeld:
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 } }
eindvoorbeeld
Het gebruik van aliassen kan een gesloten samengesteld type een naam opgeven, maar kan geen niet-afhankelijke algemene typedeclaratie zonder typeargumenten opgeven.
Voorbeeld:
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 }
eindvoorbeeld
14.5.3 Met behulp van naamruimterichtlijnen
Een using_namespace_directive importeert de typen in een naamruimte in de compilatie-eenheid of naamruimtetekst die onmiddellijk wordt geplaatst, zodat de id van elk type zonder kwalificatie kan worden gebruikt.
using_namespace_directive
: 'using' namespace_name ';'
;
Binnen liddeclaraties in een compilatie-eenheid of naamruimtebody die een using_namespace_directive bevat, kunnen de typen in de opgegeven naamruimte rechtstreeks worden verwezen.
Voorbeeld:
namespace N1.N2 { class A {} } namespace N3 { using N1.N2; class B : A {} }
Boven, binnen liddeclaraties in de
N3
naamruimte, zijn het type ledenN1.N2
rechtstreeks beschikbaar en is de klasseN3.B
dus afgeleid van klasseN1.N2.A
.eindvoorbeeld
Een using_namespace_directive importeert de typen in de opgegeven naamruimte, maar importeert geen geneste naamruimten.
Voorbeeld: In de volgende code
namespace N1.N2 { class A {} } namespace N3 { using N1; class B : N2.A {} // Error, N2 unknown }
de using_namespace_directive importeert de typen in
N1
, maar niet in de naamruimten die zijn genest .N1
De verwijzing naarN2.A
in de declaratie vanB
resultaten resulteert dus in een compilatietijdfout, omdat er geen benoemdeN2
leden binnen het bereik vallen.eindvoorbeeld
In tegenstelling tot een using_alias_directive kan een using_namespace_directive typen importeren waarvan de id's al zijn gedefinieerd in de hoofdtekst van de compilatie-eenheid of naamruimte. In feite worden namen die worden geïmporteerd door een using_namespace_directive verborgen door vergelijkbare benoemde leden in de hoofdtekst van de compilatie-eenheid of naamruimte.
Voorbeeld:
namespace N1.N2 { class A {} class B {} } namespace N3 { using N1.N2; class A {} }
Hier verwijst binnen liddeclaraties in de
N3
naamruimteA
naarN3.A
in plaatsN1.N2.A
van .eindvoorbeeld
Omdat namen dubbelzinnig kunnen zijn wanneer meer dan één geïmporteerde naamruimte dezelfde typenaam introduceert, is een using_alias_directive handig om de verwijzing ondubbelzinnig te maken.
Voorbeeld: In de volgende code
namespace N1 { class A {} } namespace N2 { class A {} } namespace N3 { using N1; using N2; class B : A {} // Error, A is ambiguous }
zowel
N1
alsN2
een lidA
bevatten, en omdatN3
beide worden geïmporteerd, is het verwijzen naarN3
A
een compilatiefout. In deze situatie kan het conflict worden opgelost door middel van de kwalificatie van verwijzingen naarA
, of door een using_alias_directive te introduceren die een bepaaldeA
optie kiest . Voorbeeld:namespace N3 { using N1; using N2; using A = N1.A; class B : A {} // A means N1.A }
eindvoorbeeld
Als meer dan één naamruimte of type dat is geïmporteerd door using_namespace_directives of using_static_directive s in dezelfde compilatie-eenheidof naamruimtetekst dezelfde naam bevat, worden verwijzingen naar die naam als een simple_name beschouwd als dubbelzinnig.
Voorbeeld:
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
bevat een typelidA
enC
bevat een statisch veldA
, en omdatN2
beide worden geïmporteerd, verwijst naarA
een simple_name dubbelzinnig is en een compilatiefout.eindvoorbeeld
Net als een using_alias_directive draagt een using_namespace_directive geen nieuwe leden bij aan de onderliggende declaratieruimte van de compilatie-eenheid of naamruimte, maar is dit in plaats daarvan alleen van invloed op de hoofdtekst van de compilatie-eenheid of naamruimte waarin deze wordt weergegeven.
De namespace_name waarnaar door een using_namespace_directive wordt verwezen, wordt op dezelfde manier opgelost als de namespace_or_type_name waarnaar wordt verwezen door een using_alias_directive. Dus using_namespace_directives in dezelfde compilatie-eenheid of naamruimtebody hebben geen invloed op elkaar en kunnen in elke volgorde worden geschreven.
14.5.4 Met statische instructies
Een using_static_directive importeert de geneste typen en statische leden die rechtstreeks in een typedeclaratie zijn opgenomen in de compilatie-eenheid of naamruimtetekst, waardoor de id van elk lid en type zonder kwalificatie kan worden gebruikt.
using_static_directive
: 'using' 'static' type_name ';'
;
Binnen liddeclaraties in een compilatie-eenheid of naamruimtebody die een using_static_directive bevat, kunnen de toegankelijke geneste typen en statische leden (behalve extensiemethoden) rechtstreeks in de declaratie van het opgegeven type rechtstreeks worden verwezen.
Voorbeeld:
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(); } } }
In de voorgaande code, binnen liddeclaraties in de
N2
naamruimte, zijn de statische leden en geneste typenN1.A
rechtstreeks beschikbaar, en dus kan de methodeN
verwijzen naar zowel de alsM
deB
leden vanN1.A
.eindvoorbeeld
Een using_static_directive importeert extensiemethoden niet rechtstreeks als statische methoden, maar maakt ze beschikbaar voor aanroepen van extensiemethoden (§12.8.9.3).
Voorbeeld:
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 } } }
de using_static_directive importeert de extensiemethode
M
inN1.A
, maar alleen als een extensiemethode. De eerste verwijzing naarM
in de hoofdtekst vanB.N
de resultaten resulteert dus in een compilatietijdfout omdat er geen benoemdeM
leden binnen het bereik vallen.eindvoorbeeld
Een using_static_directive importeert alleen leden en typen die rechtstreeks in het opgegeven type zijn gedeclareerd, niet leden en typen die zijn gedeclareerd in basisklassen.
Voorbeeld:
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 } } }
de using_static_directive importeert de methode
M2
inN1.B
, maar importeert de methodeM
niet inN1.A
. De verwijzing naarM
in de hoofdtekst vanC.N
de resultaten resulteert dus in een compilatietijdfout, omdat er geen benoemde ledenM
binnen het bereik vallen. Ontwikkelaars moeten een tweedeusing static
richtlijn toevoegen om op te geven dat de methodenN1.A
ook moeten worden geïmporteerd.eindvoorbeeld
Dubbelzinnigheden tussen meerdere using_namespace_directives en using_static_directives worden besproken in §14.5.3.
14.6 Naamruimteliddeclaraties
Een namespace_member_declaration is een namespace_declaration (§14.3) of een type_declaration (§14.7).
namespace_member_declaration
: namespace_declaration
| type_declaration
;
Een compilatie-eenheid of een hoofdtekst van een naamruimte kan namespace_member_declarations bevatten en dergelijke declaraties dragen nieuwe leden bij aan de onderliggende declaratieruimte van de inhoudseenheid of de hoofdtekst van de naamruimte.
14.7 Typedeclaraties
Een type_declaration is een class_declaration (§15.2), een struct_declaration (§16.2), een interface_declaration (§18.2), een enum_declaration (§19.2) of een delegate_declaration (§20.2).
type_declaration
: class_declaration
| struct_declaration
| interface_declaration
| enum_declaration
| delegate_declaration
;
Een type_declaration kan optreden als een declaratie op het hoogste niveau in een compilatie-eenheid of als liddeclaratie binnen een naamruimte, klasse of struct.
Wanneer een typedeclaratie voor een type T
plaatsvindt als een declaratie op het hoogste niveau in een compilatie-eenheid, is de volledig gekwalificeerde naam (§7.8.2) van de typedeclaratie hetzelfde als de niet-gekwalificeerde naam van de declaratie (§7.8.2). Wanneer een typedeclaratie voor een type T
plaatsvindt binnen een naamruimte, klasse of structdeclaratie, is de volledig gekwalificeerde naam (§7.8.3) van de typedeclaratieis S.N
, waarbij S
de volledig gekwalificeerde naam van de naamruimte, klasse of struct-declaratie is en N
de niet-gekwalificeerde naam van de declaratie is.
Een type dat in een klasse of struct is gedeclareerd, wordt een genest type genoemd (§15.3.9).
De toegestane toegangsaanpassingen en de standaardtoegang voor een typedeclaratie zijn afhankelijk van de context waarin de declaratie plaatsvindt (§7.5.2):
- Typen die zijn gedeclareerd in compilatie-eenheden of naamruimten, kunnen toegang hebben of
internal
hebbenpublic
. De standaardwaarde isinternal
toegang. - Typen die in klassen zijn gedeclareerd, kunnen toegang hebben,
protected internal
ofprivate
internal
private protected
protected
toegang hebben.public
De standaardwaarde isprivate
toegang. - Typen gedeclareerde structs kunnen toegang hebben of
internal
private
hebbenpublic
. De standaardwaarde isprivate
toegang.
Lid van gekwalificeerde alias 14.8
14.8.1 Algemeen
Met de aliaskwalificatie ::
van de naamruimte kunt u garanderen dat zoekacties voor typenamen niet worden beïnvloed door de introductie van nieuwe typen en leden. De aliasscheidingsteken voor naamruimten wordt altijd weergegeven tussen twee id's die de linker- en rechter-id's worden genoemd. In tegenstelling tot de reguliere .
kwalificatie wordt de linker-id van de ::
kwalificatie alleen opgezoekd als extern of als alias.
Een qualified_alias_member biedt expliciete toegang tot de globale naamruimte en extern of met behulp van aliassen die mogelijk worden verborgen door andere entiteiten.
qualified_alias_member
: identifier '::' identifier type_argument_list?
;
Een qualified_alias_member kan worden gebruikt als een namespace_or_type_name (§7.8) of als de linkeroperand in een member_access (§12.8.7).
Een qualified_alias_member bestaat uit twee id's, aangeduid als de linker- en rechter-id's, gescheiden door het ::
token en eventueel gevolgd door een type_argument_list. Wanneer de linker-id globaal is, wordt de globale naamruimte gezocht naar de rechter-id. Voor een andere id aan de linkerkant wordt die id opgezocht als extern of als alias (§14.4 en §14.5.2). Er treedt een compilatiefout op als er geen dergelijke alias of de alias verwijst naar een type. Als de alias verwijst naar een naamruimte, wordt die naamruimte gezocht naar de rechter-id.
Een qualified_alias_member heeft een van de volgende twee vormen:
N::I<A₁, ..., Aₑ>
, waarN
enI
vertegenwoordigt id's en<A₁, ..., Aₑ>
is een lijst met typeargumenten. (e
is altijd ten minste één.)N::I
, waarN
enI
vertegenwoordigt id's. (In dit gevale
wordt beschouwd als nul.)
Met deze notatie wordt de betekenis van een qualified_alias_member als volgt bepaald:
- Als
N
dit de idglobal
is, wordt de algemene naamruimte gezochtI
naar:- Als de globale naamruimte een naamruimte met de naam
I
e
nul bevat, verwijst de qualified_alias_member naar die naamruimte. - Als de globale naamruimte een niet-algemeen type bevat en
I
e
nul is, verwijst de qualified_alias_member naar dat type. - Als de globale naamruimte een type bevat dat
I
typeparameters bevate
, verwijst de qualified_alias_member naar dat type dat is samengesteld met de opgegeven typeargumenten. - Anders is de qualified_alias_member niet gedefinieerd en treedt er een compileertijdfout op.
- Als de globale naamruimte een naamruimte met de naam
- Als dat niet het geval is, begint u met de declaratie van de naamruimte (§14.3) onmiddellijk met de qualified_alias_member (indien van toepassing), waarbij elke declaratie van de naamruimte (indien van toepassing) wordt voortgezet en eindigt met de compilatie-eenheid met de qualified_alias_member, worden de volgende stappen geëvalueerd totdat een entiteit zich bevindt:
- Als de naamruimtedeclaratie of compilatie-eenheid een using_alias_directive bevat die N aan een type koppelt, is de qualified_alias_member niet gedefinieerd en treedt er een compilatiefout op.
- Als de naamruimtedeclaratie of compilatie-eenheid anders een extern_alias_directive of using_alias_directive bevat die aan een naamruimte is gekoppeld
N
, dan:- Als de naamruimte die is gekoppeld
N
aan een naamruimte met de naamI
e
nul is, verwijst de qualified_alias_member naar die naamruimte. - Als de naamruimte die is gekoppeld
N
aan een niet-algemeen type mete
de naamI
nul bevat, verwijst de qualified_alias_member naar dat type. - Als de naamruimte die is
N
gekoppeld aan een type bevatI
dat typeparameters bevate
, verwijst de qualified_alias_member naar dat type dat is samengesteld met de opgegeven typeargumenten. - Anders is de qualified_alias_member niet gedefinieerd en treedt er een compileertijdfout op.
- Als de naamruimte die is gekoppeld
- Anders is de qualified_alias_member niet gedefinieerd en treedt er een compileertijdfout op.
Voorbeeld: In de 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; } }
naar de klasse
A
wordt verwezenglobal::A
en wordt naar het typeSystem.Net.Sockets.Socket
verwezen.S::Socket
Het gebruik enA.x
S.Socket
zou in plaats daarvan compilatiefouten hebben veroorzaakt omdatA
enS
zou zijn omgezet in de parameters.eindvoorbeeld
Opmerking: De id
global
heeft alleen speciale betekenis wanneer deze wordt gebruikt als de linker-id van een qualified_alias_name. Het is geen trefwoord en het is zelf geen alias; het is een contextueel trefwoord (§6.4.4). In de code:class A { } class C { global.A x; // Error: global is not defined global::A y; // Valid: References A in the global namespace }
met behulp van
global.A
een compilatietijdfout omdat er geen entiteit met een naamglobal
in het bereik is. Als een entiteit met de naam Global binnen het bereik valt,global
zou inglobal.A
die entiteit zijn omgezet.Als
global
de linker-id van een qualified_alias_member altijd een zoekactie in deglobal
naamruimte veroorzaakt, zelfs als er een alias met de naam wordt gebruiktglobal
. In de 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
wordt omgezet inMyGlobalTypes.A
englobal::A
omgezet in klasseA
in de globale naamruimte.eindnotitie
14.8.2 Uniekheid van aliassen
Elke compilatie-eenheid en naamruimtetekst hebben een afzonderlijke declaratieruimte voor externe aliassen en het gebruik van aliassen. Dus, terwijl de naam van een extern alias of het gebruik van alias uniek is binnen de set externe aliassen en het gebruik van aliassen die zijn gedeclareerd in de direct bevattende compilatie-eenheid of naamruimtebody, mag een alias dezelfde naam hebben als een type of naamruimte zolang deze alleen wordt gebruikt met de ::
kwalificatie.
Voorbeeld: In het volgende:
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 } }
de naam
A
heeft twee mogelijke betekenissen in de tweede naamruimtetekst, omdat zowel de klasseA
als de using-aliasA
binnen het bereik vallen. Daarom is het gebruik vanA
in de gekwalificeerde naamA.Stream
dubbelzinnig en wordt er een compilatiefout opgetreden. Het gebruik vanA
met de::
kwalificatie is echter geen fout, omdatA
deze alleen wordt opgezoekd als een naamruimtealias.eindvoorbeeld
ECMA C# draft specification