Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
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.6) en globale 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 global_using_directivegevolgd door nul of meer using_directivegevolgd door nul of één global_attributes gevolgd door een compilation_unit_body. Een compilation_unit_body kan nul of meer statement_listzijn gevolgd door nul of meer namespace_member_declarations, of een file_scoped_namespace_declaration. De compilation_unit definieert de algehele structuur van de invoer.
compilation_unit
: extern_alias_directive* using_directive* global_attributes? compilation_unit_body
;
compilation_unit_body
: statement_list* namespace_member_declaration*
| file_scoped_namespace_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 global_using_directives, using_directives, global_attributes en compilation_unit_body van die compilatie-eenheid, maar hebben geen invloed op andere compilatie-eenheden.
De using_directivevan een compilatie-eenheid zijn van invloed op de global_attributes en compilation_unit_body van die compilatie-eenheid, maar hebben geen invloed op andere compilatie-eenheden.
De global_using_directives van een compilatie-eenheid zijn van invloed op de global_attributes en namespace_member_declarationvan alle compilatie-eenheden in het programma.
De global_attributes (§23.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_declarations of file_scoped_namespace_declaration van elke compilatie-eenheid van een programma dragen leden bij aan één declaratieruimte genaamd de globale naamruimte.
Een file_scoped_namespace_declaration draagt bij aan leden die overeenkomen met de namespace_declaration waaraan het semantisch gelijkwaardig is (§14.3).
Example:
// 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
AenB. 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 naamruimte van het trefwoord, gevolgd door een naamruimtenaam en hoofdtekst, eventueel gevolgd door een puntkomma. Een file_scoped_namespace_declaration bestaat uit het trefwoord namespace, gevolgd door een naamruimtenaam, een puntkomma en een optionele lijst met extern_alias_directives, using_directiveen type_declarations.
namespace_declaration
: 'namespace' qualified_identifier namespace_body ';'?
;
file_scoped_namespace_declaration
: 'namespace' qualified_identifier ';' extern_alias_directive* using_directive*
type_declaration*
;
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 buitennaamruimte. In beide gevallen moet de naam van een naamruimte uniek zijn binnen de naamruimte die de naamruimte bevat.
Een file_scoped_namespace_declaration kan alleen optreden als een declaratie op het hoogste niveau in een compilation_unit. Als zodanig wordt de gedeclareerde naamruimte lid van de globale naamruimte.
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_directiveworden weergegeven vóór eventuele lidverklaringen.
Binnen een file_scoped_namespace_declaration 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 type_declarationdragen leden bij aan de declaratieruimte van de naamruimte. Houd er rekening mee dat alle using_directives worden weergegeven vóór een typedeclaratie.
De qualified_identifier van een namespace_declaration en file_scoped_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.
Example:
namespace N1.N2 { class A {} class B {} }semantisch gelijk is aan
namespace N1 { namespace N2 { class A {} class B {} } }eindvoorbeeld
Met een file_scoped_namespace_declaration kan een naamruimtedeclaratie zonder een bijbehorend { … } blok worden geschreven.
Example:
namespace Name; using System; class C { }semantisch gelijk is aan
namespace Name { using System; class C { } }eindvoorbeeld
Een file_scoped_namespace_declaration wordt hetzelfde behandeld als een namespace_declaration op dezelfde locatie in de compilation_unit met dezelfde qualified_identifier. De extern_alias_directive, using_directiveen type_declarationvan die file_scoped_namespace_declaration fungeren alsof ze in dezelfde volgorde in de namespace_body van die namespace_declaration zijn verklaard.
Opmerking: Zoals bepaald door de grammatica, kan een compilatie-eenheid niet zowel een file_scoped_namespace_declaration als een namespace_declaration bevatten. Het mag niet meerdere file_scoped_namespace_declarations bevatten. Het mag geen file_scoped_namespace_declaration en een instructie op het hoogste niveau bevatten. type_declarations kunnen niet voorafgaan aan een file_scoped_namespace_declaration. eindnotitie
Verschillende compilatie-eenheden kunnen bijdragen aan dezelfde naamruimte met behulp van of beide van de namespace_member_declaration of file_scoped_namespace_declaration syntaxis.
Naamruimten zijn open-ended en twee naamruimtedeclaraties met dezelfde volledig gekwalificeerde naam (§7.8.3) 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.AenN1.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
Met een file_scoped_namespace_declaration kan een naamruimtedeclaratie zonder een bijbehorend { … } blok worden geschreven.
Example:
namespace Name; using System; class C { }semantisch gelijk is aan
namespace Name { using System; class C { } }eindvoorbeeld
Een file_scoped_namespace_declaration wordt hetzelfde behandeld als een namespace_declaration op dezelfde locatie in de compilation_unit met dezelfde qualified_identifier. De extern_alias_directive, using_directiveen type_declarationvan die file_scoped_namespace_declaration fungeren alsof ze in dezelfde volgorde in de namespace_body van die namespace_declaration zijn verklaard.
Opmerking: Zoals bepaald door de grammatica, kan een compilatie-eenheid niet zowel een file_scoped_namespace_declaration als een namespace_declaration bevatten. Het mag niet meerdere file_scoped_namespace_declarations bevatten. Het mag geen file_scoped_namespace_declaration en een instructie op het hoogste niveau bevatten. type_declarations kunnen niet voorafgaan aan een file_scoped_namespace_declaration. eindnotitie
Verschillende compilatie-eenheden kunnen bijdragen aan dezelfde naamruimte met behulp van of beide van de namespace_member_declaration of file_scoped_namespace_declaration syntaxis.
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 wordt beschreven in §7.7.1.
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 globalte 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.6.2 voor meer gedetailleerde bespreking van extern_alias_directiveen using_alias_directives.
alias is een contextueel trefwoord (§6.4.4) en heeft alleen een speciale betekenis wanneer het trefwoord direct volgt extern op 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
XY, 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
XenY, maar de werkelijke definities van de aliassen zijn extern voor het programma. Naar de identieke benoemdeN.Bklassen kan nu worden verwezen alsX.N.BenY.N.B, of, met behulp van de aliaskwalificatie van de naamruimte,X::N.BenY::N.B. eindvoorbeeld
14.5 Global using directives
14.5.1 Algemeen
Een globale gebruiksrichtlijn is een using-instructie (§14.6) op het hoogste niveau van een compilatie-eenheid.
global_using_directive
: global_using_alias_directive
| global_using_namespace_directive
| global_using_static_directive
;
Opmerking: Het bereik van een global_using_directive wordt uitgebreid over de namespace_member_declarationvan alle compilatie-eenheden binnen het programma. Het bereik van een global_using_directive omvat specifiek geen andere global_using_directives. Peer-global_using_directives of die van een andere compilatie-eenheid hebben dus geen invloed op elkaar en de volgorde waarin ze zijn geschreven, is onbelangrijk. Het bereik van een global_using_directive omvat niet specifiek using_directives onmiddellijk opgenomen in een compilatie-eenheid van het programma.
Het effect van het toevoegen van een global_using_directive aan een programma kan worden beschouwd als het effect van het toevoegen van een vergelijkbare using_directive die wordt omgezet in dezelfde doelnaamruimte of type aan elke compilatie-eenheid van het programma. Het doel van een global_using_directive wordt echter opgelost in de context van de compilatie-eenheid die deze bevat. eindnotitie
14.5.2 Global met aliasrichtlijnen
Een global_using_alias_directive introduceert een id die fungeert als een alias voor een naamruimte of type in het programma.
global_using_alias_directive
: 'global' using_alias_directive
;
Binnen liddeclaraties in een compilatie-eenheid van een programma dat een global_using_alias_directive bevat, kan de id die door de global_using_alias_directive wordt geïntroduceerd, worden gebruikt om te verwijzen naar de opgegeven naamruimte of het opgegeven type.
De id van een global_using_alias_directive is uniek binnen de declaratieruimte van een compilatie-eenheid van een programma dat de global_using_alias_directive bevat.
Net als gewone leden worden namen die door global_using_alias_directives worden geïntroduceerd, verborgen door vergelijkbare benoemde leden in geneste bereiken.
De volgorde waarin global_using_alias_directives zijn geschreven, heeft geen betekenis en de oplossing van de namespace_or_type_name waarnaar wordt verwezen door een global_using_alias_directive wordt niet beïnvloed door de global_using_alias_directive zelf of door andere global_using_directives of using_directivein het programma. Met andere woorden, de namespace_or_type_name van een global_using_alias_directive wordt opgelost alsof de compilatie-eenheid onmiddellijk geen using_directives had en het hele bevat programma geen global_using_directives. Een global_using_alias_directive kan echter worden beïnvloed door extern_alias_directives in de onmiddellijk met compilatie-eenheid.
Een global_using_alias_directive kan een alias maken voor elke naamruimte of elk type.
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.
Het gebruik van aliassen kan een gesloten samengesteld type een naam opgeven, maar kan geen niet-afhankelijke algemene typedeclaratie zonder typeargumenten opgeven.
14.5.3 Global met behulp van naamruimterichtlijnen
Een global_using_namespace_directive importeert de typen in een naamruimte in het programma, waardoor de id van elk type zonder kwalificatie kan worden gebruikt.
global_using_namespace_directive
: 'global' using_namespace_directive
;
Binnen liddeclaraties in een programma dat een global_using_namespace_directive bevat, kunnen de typen in de opgegeven naamruimte rechtstreeks worden verwezen.
Een global_using_namespace_directive importeert de typen in de opgegeven naamruimte, maar importeert geen geneste naamruimten.
In tegenstelling tot een global_using_alias_directive kan een global_using_namespace_directive typen importeren waarvan de id's al zijn gedefinieerd in een compilatie-eenheid van het programma. In een bepaalde compilatie-eenheid worden de namen die door een global_using_namespace_directive in het programma worden geïmporteerd, verborgen door vergelijkbare benoemde leden in de compilatie-eenheid.
Wanneer meer dan één naamruimte of type dat is geïmporteerd door global_using_namespace_directives of global_using_static_directivein hetzelfde programma typen met dezelfde naam bevat, worden verwijzingen naar die naam als een type_name als dubbelzinnig beschouwd.
Bovendien worden verwijzingen naar die naam als een simple_name beschouwd wanneer meer dan één naamruimte of type dat door global_using_namespace_directives of global_using_static_directivein hetzelfde programma is geïmporteerd, typen of leden met dezelfde naam bevatten.
De namespace_name waarnaar door een global_using_namespace_directive wordt verwezen, wordt op dezelfde manier opgelost als de namespace_or_type_name waarnaar wordt verwezen door een global_using_alias_directive. Dus global_using_namespace_directives in hetzelfde programma hebben geen invloed op elkaar en kunnen in elke volgorde worden geschreven.
14.5.4 Global met behulp van statische instructies
Een global_using_static_directive importeert de geneste typen en statische leden die rechtstreeks zijn opgenomen in een typedeclaratie in het betreffende programma, waardoor de id van elk lid en type zonder kwalificatie kan worden gebruikt.
global_using_static_directive
: 'global' using_static_directive
;
Binnen liddeclaraties in een programma dat een global_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.
Een global_using_static_directive importeert extensiemethoden niet rechtstreeks als statische methoden, maar maakt ze beschikbaar voor aanroepen van extensiemethoden.
Een global_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.
Dubbelzinnigheden tussen meerdere global_using_namespace_directiveen global_using_static_directives worden besproken in §14.5.3.
14.6 Met behulp van instructies
14.6.1 Algemeen
Een using-instructie 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_names (§7.8) en simple_names (§12.8.4), maar in tegenstelling tot declaraties dragen using_directives geen 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.6.2) introduceert een alias voor een naamruimte of type.
Een using_namespace_directive (§14.6.3) importeert het type leden van een naamruimte.
Een using_static_directive (§14.6.4) importeert de geneste typen en statische leden van een type.
Het bereik van een using_directive wordt beschreven in §7.7.1.
14.6.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.
Example:
namespace N1.N2 { class A {} } namespace N3 { using A = N1.N2.A; class B: A {} }Boven, binnen liddeclaraties in de
N3naamruimte,Ais een alias voorN1.N2.A, en dus klasseN3.Bafgeleid van klasseN1.N2.A. Hetzelfde effect kan worden verkregen door een aliasRte maken voorN1.N2en 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 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 bijbehorende naamruimte.
Voorbeeld: bijvoorbeeld:
namespace N1 { extern alias N2; class B : N2::A {} }Boven is binnen liddeclaraties in de
N1naamruimteN2een alias voor een naamruimte waarvan de definitie extern is voor de broncode van het programma. KlasseN1.Bis afgeleid van klasseN2.A. Hetzelfde effect kan worden verkregen door een aliasAte maken voorN2.Aen 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 binnen een bepaalde compilatie-eenheid of naamruimtebody, 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
R1enR2alleen uitbreiden naar liddeclaraties in de naamruimtetekst waarin ze zijn opgenomen, dusR1enR2zijn 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.
Example:
extern alias X; extern alias Y; using X = N1.N2; // Error: alias X already exists class Y {} // OkDe using-alias met de naam
Xveroorzaakt een fout, omdat er al een alias is met de naamXin dezelfde compilatie-eenheid. De klasse met de naamYconflicteren niet met de externe alias,Yomdat 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 vanBresultaten in een fout, omdatN3bevat een lid met de naamBen de naamruimtebody die ook een alias met naamBdeclareert ; eveneens voorA. Naar de klasseN3.Bkan worden verwezen alsN3.Bofglobal::N3.B. De aliasAkan worden gebruikt in een qualified-alias-member (§14.9), zoalsA::B. De aliasBis in wezen nutteloos. Het kan niet worden gebruikt in een qualified_alias_member omdat alleen naamruimtealiassen kunnen worden gebruikt in een qualified_alias_member enBaliassen 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.Ain de declaratie vanBoorzaken een compilatietijdfout omdatRverwijst 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_directive szijn 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_directivein 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. En als de using_alias_directive onmiddellijk is opgenomen in een compilatie-eenheid, wordt dit niet beïnvloed door de global_using_directives in het programma. Met andere woorden, de namespace_or_type_name van een using_alias_directive wordt opgelost alsof de direct bevattende hoofdtekst van de compilatie-eenheid of naamruimte geen using_directiveen, als de using_alias_directive direct in een compilatie-eenheid is opgenomen, het programma geen global_using_directives had, 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.Aen zijn gelijkwaardig enR2.Aallemaal 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_directiveen using_directives van de naamruimteteksten en compilatie-eenheid die dat deel omsluit, beschouwd. Dit kan ertoe leiden dat dezelfde id verschillende betekenissen in verschillende delen heeft.
Example:
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.
Example:
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.6.3 Met behulp van naamruimterichtlijnen
Een using_namespace_directive importeert de typen in een naamruimte in de direct tussenliggende compilatie-eenheid of naamruimtetekst, waardoor de id van elk type zonder kwalificatie kan worden gebruikt.
using_namespace_directive
: 'using' namespace_name ';'
;
Binnen liddeclaraties in een compilatie-eenheid of naamruimtetekst die een using_namespace_directive bevat, kunnen de typen in de opgegeven naamruimte rechtstreeks worden verwezen.
Example:
namespace N1.N2 { class A {} } namespace N3 { using N1.N2; class B : A {} }Boven, binnen liddeclaraties in de
N3naamruimte, zijn het type ledenN1.N2rechtstreeks beschikbaar en is de klasseN3.Bdus 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 .N1De verwijzing naarN2.Ain de declaratie vanBresultaten resulteert dus in een compilatietijdfout, omdat er geen benoemdeN2leden 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. Namen die door een using_namespace_directive worden geïmporteerd, worden verborgen door vergelijkbare benoemde leden in de hoofdtekst van de compilatie-eenheid of naamruimte.
Example:
namespace N1.N2 { class A {} class B {} } namespace N3 { using N1.N2; class A {} }Hier verwijst binnen liddeclaraties in de
N3naamruimteAnaarN3.Ain plaatsN1.N2.Avan .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
N1alsN2een lidAbevatten, en omdatN3beide worden geïmporteerd, is het verwijzen naarAN3een 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 bepaaldeAkiest . 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 indezelfde compilatie-eenheid of naamruimtetekst dezelfde naam bevat, worden verwijzingen naar die naam als een simple_name beschouwd als dubbelzinnig.
Example:
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 } } }
N1bevat een typelidAenCbevat een statisch veldA, en omdatN2beide worden geïmporteerd, verwijst naarAeen 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 heeft dit alleen invloed op de hoofdtekst van de compilatie-eenheid of naamruimte waarin deze wordt weergegeven.
De namespace_name waarnaar wordt verwezen door een using_namespace_directive wordt opgelost op dezelfde manier 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.6.4 Met statische instructies
Een using_static_directive importeert de geneste typen en statische leden rechtstreeks in een typedeclaratie 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.
Example:
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
N2naamruimte, zijn de statische leden en geneste typenN1.Arechtstreeks beschikbaar, en dus kan de methodeNverwijzen naar zowel de alsBdeMleden vanN1.A.eindvoorbeeld
Een using_static_directive importeert extensiemethoden niet rechtstreeks als statische methoden, maar maakt ze beschikbaar voor aanroepen van extensiemethoden (§12.8.10.3).
Example:
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
MinN1.A, maar alleen als extensiemethode. De eerste verwijzing naarMin de hoofdtekst vanB.Nde resultaten resulteert dus in een compilatietijdfout omdat er geen benoemdeMleden 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.
Example:
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
M2inN1.B, maar importeert de methodeMniet inN1.A. De verwijzing naarMin de hoofdtekst vanC.Nde resultaten resulteert dus in een compilatietijdfout, omdat er geen benoemde ledenMbinnen het bereik vallen. Ontwikkelaars moeten een tweedeusing staticrichtlijn toevoegen om op te geven dat de methodenN1.Aook moeten worden geïmporteerd.eindvoorbeeld
Dubbelzinnigheden tussen meerdere using_namespace_directives en using_static_directives worden besproken in §14.6.3.
14.7 Naamruimteliddeclaraties
Een namespace_member_declaration is ofwel een namespace_declaration (§14.3) of een type_declaration (§14.8).
namespace_member_declaration
: namespace_declaration
| type_declaration
;
Een compilatie-eenheid of een hoofdtekst van een naamruimte kan namespace_member_declaration sbevatten en dergelijke declaraties dragen nieuwe leden bij aan de onderliggende declaratieruimte van de compilatie-eenheid of naamruimtetekst.
14.8 Typedeclaraties
Een type_declaration is een class_declaration (§15.2), een struct_declaration (§16.2), een interface_declaration (§19.2), een enum_declaration (§20.2) of een delegate_declaration (§21.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.3) 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 struct-declaratie, is de volledig gekwalificeerde naam (§7.8.3) van de declaratie S.Nvan het type , waar 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 is gedeclareerd binnen een klasse, interface of struct, wordt een geneste 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
publichebbeninternal. De standaardwaarde isinternaltoegang. - Typen die in klassen zijn gedeclareerd, kunnen toegang hebben,
publicofprotected internalprotectedprivate protectedinternaltoegang hebben.privateDe standaardwaarde isprivatetoegang. - Typen gedeclareerde structs kunnen toegang hebben of
publicinternalhebbenprivate. De standaardwaarde isprivatetoegang.
14.9 Gekwalificeerde aliaslid
14.9.1 Algemeen
Met 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 linker-id wordt die id opgezocht als extern of als alias (§14.4 en §14.6.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ₑ>, waarNenIvertegenwoordigt id's en<A₁, ..., Aₑ>is een lijst met typeargumenten. (eis altijd ten minste één.) -
N::I, waarNenIvertegenwoordigt id's. (In dit gevalewordt beschouwd als nul.)
Met deze notatie wordt de betekenis van een qualified_alias_member als volgt bepaald:
- Als
Ndit de idglobalis, wordt de algemene naamruimte gezochtInaar:- Als de globale naamruimte een naamruimte met de naam nul
Iebevat, verwijst de qualified_alias_member naar die naamruimte. - Als de globale naamruimte een niet-algemeen type bevat
Ienenul is, verwijst de qualified_alias_member naar dat type. - Als de globale naamruimte een type bevat dat
Itypeparameters 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 compilatiefout op.
- Als de globale naamruimte een naamruimte met de naam nul
- Anders worden, beginnend met de declaratie van de naamruimte (§14.3) onmiddellijk met de qualified_alias_member (indien van toepassing), verdergaan met elke declaratie van de naamruimte (indien van toepassing) en eindigend 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 koppelt aan een type of wanneer een compilatie-eenheid wordt bereikt, bevat het programma een global_using_alias_directive die aan een type wordt gekoppeld
N, is de qualified_alias_member niet gedefinieerd en treedt er een compilatiefout op. - Als de naamruimtedeclaratie of compilatie-eenheid een extern_alias_directive of using_alias_directive bevat die aan een naamruimte wordt gekoppeld
N, of wanneer een compilatie-eenheid wordt bereikt, bevat het programma een global_using_alias_directive die aan een naamruimte wordt gekoppeldN. Vervolgens:- Als de naamruimte die is gekoppeld aan
Neen naamruimte bevat met de naamIenenul is, verwijst de qualified_alias_member naar die naamruimte. - Als de naamruimte die is gekoppeld aan
Neen niet-algemeen type bevat met de naamIenenul is, verwijst de qualified_alias_member naar dat type. - Als de naamruimte die aan
Nis gekoppeld een type genaamdIbevat metetypeparameters, verwijst het -qualified_alias_member naar dat type, geconstrueerd met de gegeven typeargumenten. - Anders is de qualified_alias_member niet gedefinieerd en treedt er een compilatiefout op.
- Als de naamruimte die is gekoppeld aan
- Als de naamruimtedeclaratie of compilatie-eenheid een using_alias_directive bevat die N koppelt aan een type of wanneer een compilatie-eenheid wordt bereikt, bevat het programma een global_using_alias_directive die aan een type wordt gekoppeld
- Anders is de qualified_alias_member niet gedefinieerd en treedt er een compilatiefout 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
Awordt verwezenglobal::Aen wordt naar het typeSystem.Net.Sockets.Socketverwezen.S::SocketHet gebruik enA.xS.Socketzou in plaats daarvan compilatiefouten hebben veroorzaakt omdatAenSzou zijn omgezet in de parameters.eindvoorbeeld
Opmerking: De id
globalheeft 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.Aeen compilatietijdfout omdat er geen entiteit met een naamglobalin het bereik is. Als een entiteit met de naam Global binnen het bereik valt,globalzou inglobal.Adie entiteit zijn omgezet.Als
globalde linker-id van een qualified_alias_member altijd een zoekactie in deglobalnaamruimte veroorzaakt, zelfs als er een using-alias met de naam is.globalIn 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.Awordt omgezet inMyGlobalTypes.Aenglobal::Aomgezet in klasseAin de globale naamruimte.eindnotitie
14.9.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
Aheeft twee mogelijke betekenissen in de tweede naamruimtetekst, omdat zowel de klasseAals de using-aliasAbinnen het bereik vallen. Daarom is het gebruik vanAin de gekwalificeerde naamA.Streamdubbelzinnig en wordt er een compilatiefout opgetreden. Het gebruik vanAmet de::kwalificatie is echter geen fout, omdatAdeze alleen wordt opgezoekd als een naamruimtealias.eindvoorbeeld
ECMA C# draft specification