Delen via


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 en B. 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 en N1.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 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.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 en Y, maar de werkelijke definities van de aliassen zijn extern voor het programma. Naar de identieke benoemde N.B klassen kan nu worden verwezen als X.N.B en Y.N.B, of, met behulp van de aliaskwalificatie van de naamruimte, X::N.B en Y::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 voor N1.N2.A, en dus klasse N3.B afgeleid van klasse N1.N2.A. Hetzelfde effect kan worden verkregen door een alias R te maken voor N1.N2 en vervolgens te verwijzen naar R.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 naamruimte N2 een alias voor een naamruimte waarvan de definitie extern is voor de broncode van het programma. Klasse N1.B is afgeleid van klasse N2.A. Hetzelfde effect kan worden verkregen door een alias A te maken voor N2.A en vervolgens te verwijzen naar A:

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 en R2 alleen uitbreiden naar liddeclaraties in de naamruimtetekst waarin ze zijn opgenomen, dus R1 en R2 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 naam X in dezelfde compilatie-eenheid. De klasse met de naam Y 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 van B resultaten in een fout, omdat N3 bevat een lid met de naam B en de naamruimtebody die ook een alias met naam Bdeclareert ; eveneens voor A. Naar de klasse N3.B kan worden verwezen als N3.B of global::N3.B. De alias A kan worden gebruikt in een qualified-alias-member (§14.8), zoals A::B. De alias B 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 en B 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 van B oorzaken een compilatietijdfout omdat R verwijst naar N3.R, niet N1.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.Aen zijn gelijkwaardig en R2.A allemaal verwijzen naar de klassedeclaratie waarvan de volledig gekwalificeerde naam is N1.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 leden N1.N2 rechtstreeks beschikbaar en is de klasse N3.B dus afgeleid van klasse N1.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 naar N2.A in de declaratie van B resultaten resulteert dus in een compilatietijdfout, omdat er geen benoemde N2 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 naamruimte A naar N3.A in plaats N1.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 N1 als N2 een lid Abevatten, en omdat N3 beide worden geïmporteerd, is het verwijzen naar N3 A een compilatiefout. In deze situatie kan het conflict worden opgelost door middel van de kwalificatie van verwijzingen naar A, of door een using_alias_directive te introduceren die een bepaalde Aoptie 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 typelid Aen C bevat een statisch veld A, en omdat N2 beide worden geïmporteerd, verwijst naar A 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 typen N1.A rechtstreeks beschikbaar, en dus kan de methode N verwijzen naar zowel de als M de B leden van N1.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 in N1.A, maar alleen als een extensiemethode. De eerste verwijzing naar M in de hoofdtekst van B.N de resultaten resulteert dus in een compilatietijdfout omdat er geen benoemde M 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 in N1.B, maar importeert de methode M niet in N1.A. De verwijzing naar M in de hoofdtekst van C.N de resultaten resulteert dus in een compilatietijdfout, omdat er geen benoemde leden M binnen het bereik vallen. Ontwikkelaars moeten een tweede using static richtlijn toevoegen om op te geven dat de methoden N1.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 is internal toegang.
  • Typen die in klassen zijn gedeclareerd, kunnen toegang hebben, protected internalof private internalprivate protectedprotectedtoegang hebben.public De standaardwaarde is private toegang.
  • Typen gedeclareerde structs kunnen toegang hebben of internalprivate hebbenpublic. De standaardwaarde is private 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ₑ>, waar N en I vertegenwoordigt id's en <A₁, ..., Aₑ> is een lijst met typeargumenten. (e is altijd ten minste één.)
  • N::I, waar N en I vertegenwoordigt id's. (In dit geval e wordt beschouwd als nul.)

Met deze notatie wordt de betekenis van een qualified_alias_member als volgt bepaald:

  • Als N dit de id globalis, wordt de algemene naamruimte gezocht Inaar:
    • 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 bevat e , 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 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 gekoppeldN, dan:
      • Als de naamruimte die is gekoppeld N aan een naamruimte met de naam I e nul is, verwijst de qualified_alias_member naar die naamruimte.
      • Als de naamruimte die is gekoppeld N aan een niet-algemeen type met e de naam I nul bevat, verwijst de qualified_alias_member naar dat type.
      • Als de naamruimte die is N gekoppeld aan een type bevat I dat typeparameters bevat e , 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.
  • 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 verwezen global::A en wordt naar het type System.Net.Sockets.Socket verwezen.S::Socket Het gebruik en A.x S.Socket zou in plaats daarvan compilatiefouten hebben veroorzaakt omdat A en S 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 naam global in het bereik is. Als een entiteit met de naam Global binnen het bereik valt, global zou in global.A die entiteit zijn omgezet.

Als global de linker-id van een qualified_alias_member altijd een zoekactie in de global naamruimte veroorzaakt, zelfs als er een alias met de naam wordt gebruikt global. 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 in MyGlobalTypes.A en global::A omgezet in klasse A 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 klasse A als de using-alias A binnen het bereik vallen. Daarom is het gebruik van A in de gekwalificeerde naam A.Stream dubbelzinnig en wordt er een compilatiefout opgetreden. Het gebruik van A met de :: kwalificatie is echter geen fout, omdat A deze alleen wordt opgezoekd als een naamruimtealias.

eindvoorbeeld