Dela via


14 namnområden

14.1 Allmänt

C#-program ordnas med hjälp av namnområden. Namnrymder används både som ett "internt" organisationssystem för ett program och som ett "externt" organisationssystem – ett sätt att presentera programelement som exponeras för andra program.

Användning av direktiv (§14.5) tillhandahålls för att underlätta användningen av namnområden.

14.2 Kompileringsenheter

En compilation_unit består av noll eller fler extern_alias_directiveföljt av noll eller fler using_directiveföljt av noll eller en global_attributes följt av noll eller fler namespace_member_declarations. Compilation_unit definierar den övergripande strukturen för indata.

compilation_unit
    : extern_alias_directive* using_directive* global_attributes?
      namespace_member_declaration*
    ;

Ett C#-program består av en eller flera kompileringsenheter. När ett C#-program kompileras bearbetas alla kompileringsenheter tillsammans. Kompileringsenheter kan därför vara beroende av varandra, möjligen på ett cirkulärt sätt.

Extern_alias_directive för en kompileringsenhet påverkar using_directives, global_attributes och namespace_member_declarationi den kompileringsenheten, men har ingen effekt på andra kompileringsenheter.

Using_directive för en kompileringsenhet påverkar global_attributes och namespace_member_declarationför den kompileringsenheten, men påverkar inte andra kompileringsenheter.

Den global_attributes (§22.3) av en kompileringsenhet tillåter specifikation av attribut för målsammansättningen och modulen. Sammansättningar och moduler fungerar som fysiska containrar för typer. En sammansättning kan bestå av flera fysiskt separata moduler.

De namespace_member_declarationför varje kompileringsenhet i ett program bidrar med medlemmar till ett enda deklarationsutrymme som kallas globalt namnområde.

Exempel:

// File A.cs:
class A {}
// File B.cs:
class B {}

De två kompileringsenheterna bidrar till det enskilda globala namnområdet, i det här fallet deklarerar de två klasserna med de fullständigt kvalificerade namnen A och B. Eftersom de två kompileringsenheterna bidrar till samma deklarationsutrymme skulle det ha varit ett fel om var och en innehöll en deklaration av en medlem med samma namn.

slutexempel

14.3 Namnområdesdeklarationer

En namespace_declaration består av nyckelordets namnområde följt av ett namnområdesnamn och en brödtext, eventuellt följt av ett semikolon.

namespace_declaration
    : 'namespace' qualified_identifier namespace_body ';'?
    ;

qualified_identifier
    : identifier ('.' identifier)*
    ;

namespace_body
    : '{' extern_alias_directive* using_directive*
      namespace_member_declaration* '}'
    ;

En namespace_declaration kan inträffa som en deklaration på toppnivå i en compilation_unit eller som en medlemsdeklaration inom en annan namespace_declaration. När en namespace_declaration inträffar som en toppnivådeklaration i en compilation_unit blir namnområdet medlem i det globala namnområdet. När en namespace_declaration inträffar inom en annan namespace_declaration blir det inre namnområdet medlem i det yttre namnområdet. I båda fallen ska namnet på ett namnområde vara unikt inom det innehållande namnområdet.

Namnområden är implicita public och deklarationen av ett namnområde kan inte innehålla några åtkomstmodifierare.

Inom en namespace_body importerar den valfria using_directivenamnen på andra namnområden, typer och medlemmar, så att de kan refereras direkt i stället för via kvalificerade namn. Den valfria namespace_member_declarationbidrar medlemmar till namnområdets deklarationsutrymme. Observera att alla using_directiveska visas före eventuella medlemsdeklarationer.

Qualified_identifier för en namespace_declaration kan vara en enda identifierare eller en sekvens med identifierare avgränsade med "." token. Det senare formuläret tillåter ett program att definiera ett kapslat namnområde utan att lexikalt kapsla flera namnområdesdeklarationer.

Exempel:

namespace N1.N2
{
    class A {}
    class B {}
}

är semantiskt likvärdigt med

namespace N1
{
    namespace N2
    {
        class A {}
        class B {}
    }
}

slutexempel

Namnområden är öppna och två namnområdesdeklarationer med samma fullständigt kvalificerade namn (§7.8.2) bidrar till samma deklarationsutrymme (§7.3).

Exempel: I följande kod

namespace N1.N2
{
    class A {}
}

namespace N1.N2
{
    class B {}
}

de två namnområdesdeklarationerna ovan bidrar till samma deklarationsutrymme, i det här fallet deklarera två klasser med de fullständigt kvalificerade namnen N1.N2.A och N1.N2.B. Eftersom de två deklarationerna bidrar till samma deklarationsutrymme skulle det ha varit ett fel om var och en innehöll en deklaration av en medlem med samma namn.

slutexempel

14.4 Externa aliasdirektiv

En extern_alias_directive introducerar en identifierare som fungerar som ett alias för ett namnområde. Specifikationen för det aliaserade namnområdet är externt för programmets källkod och gäller även för kapslade namnområden i det aliaserade namnområdet.

extern_alias_directive
    : 'extern' 'alias' identifier ';'
    ;

Omfånget för en extern_alias_directive sträcker sig över using_directives, global_attributes och namespace_member_declarationav dess omedelbart innehållande compilation_unit eller namespace_body.

I en kompileringsenhet eller namnområdestext som innehåller en extern_alias_directive kan identifieraren som introducerades av extern_alias_directive användas för att referera till det aliaserade namnområdet. Det är ett kompileringsfel för att identifieraren ska vara ordet global.

Aliaset som introduceras av en extern_alias_directive liknar det alias som introducerades av en using_alias_directive. Mer detaljerad information om extern_alias_directives och using_alias_directives finns i §14.5.2.

alias är ett kontextuellt nyckelord (§6.4.4) och har endast särskild betydelse när det omedelbart följer nyckelordet extern i en extern_alias_directive.

Ett fel uppstår om ett program deklarerar ett externt alias som ingen extern definition har angetts för.

Exempel: Följande program deklarerar och använder två externa alias och X , som var och Yen representerar roten i en distinkt namnområdeshierarki:

extern alias X;
extern alias Y;

class Test
{
    X::N.A a;
    X::N.B b1;
    Y::N.B b2;
    Y::N.C c;
}

Programmet deklarerar förekomsten av externa alias X och Y, men de faktiska definitionerna av aliasen är externa för programmet. De identiskt namngivna N.B klasserna kan nu refereras till som X.N.B och Y.N.B, eller, med hjälp av namnområdets aliaskvalificerare, X::N.B och Y::N.B. slutexempel

14.5 Användning av direktiv

14.5.1 Allmänt

Med hjälp av direktiv underlättas användningen av namnområden och typer som definierats i andra namnområden. Användning av direktiv påverkar namnmatchningsprocessen för namespace_or_type_names (§7.8) och simple_name(§12.8.4), men till skillnad från deklarationer bidrar using_directiveinte nya medlemmar till de underliggande deklarationsutrymmena i kompileringsenheterna eller namnrymderna inom vilka de används.

using_directive
    : using_alias_directive
    | using_namespace_directive
    | using_static_directive    
    ;

En using_alias_directive (§14.5.2) introducerar ett alias för ett namnområde eller en typ.

En using_namespace_directive (§14.5.3) importerar typmedlemmarna i ett namnområde.

En using_static_directive (§14.5.4) importerar kapslade typer och statiska medlemmar av en typ.

Omfånget för en using_directive sträcker sig över namespace_member_declarations av dess omedelbart innehållande kompileringsenhet eller namnområdestext. Omfånget för en using_directive innehåller inte dess peer-using_directive s. Därför påverkar peer-using_directive inte varandra, och ordningen i vilken de skrivs är obetydlig. Omfånget för en extern_alias_directive innehåller däremot de using_directivesom definierats i samma kompileringsenhet eller namnområdestext.

14.5.2 Använda aliasdirektiv

En using_alias_directive introducerar en identifierare som fungerar som ett alias för ett namnområde eller en typ i den omedelbart omslutande kompileringsenheten eller namnområdestexten.

using_alias_directive
    : 'using' identifier '=' namespace_or_type_name ';'
    ;

I globala attribut och medlemsdeklarationer i en kompileringsenhet eller namnområdestext som innehåller en using_alias_directive kan identifieraren som introducerades av using_alias_directive användas för att referera till det angivna namnområdet eller typen.

Exempel:

namespace N1.N2
{
    class A {}
}
namespace N3
{
    using A = N1.N2.A;

    class B: A {}
}

Ovan, inom medlemsdeklarationer i namnområdet, A är ett alias för N1.N2.A, och därför härleds klassen N3.B från klassen N1.N2.A.N3 Samma effekt kan erhållas genom att skapa ett alias R för N1.N2 och sedan referera till R.A:

namespace N3
{
    using R = N1.N2;

    class B : R.A {}
}

slutexempel

Inom användning av direktiv, globala attribut och medlemsdeklarationer i en kompileringsenhet eller namnområdestext som innehåller en extern_alias_directive kan identifieraren som introducerades av extern_alias_directive användas för att referera till det associerade namnområdet.

Exempel: Till exempel:

namespace N1
{
    extern alias N2;

    class B : N2::A {}
}

Ovan, inom medlemsdeklarationer i N1 namnområdet, N2 är ett alias för ett namnområde vars definition är extern mot programmets källkod. Klassen N1.B härleds från klassen N2.A. Samma effekt kan erhållas genom att skapa ett alias A för N2.A och sedan referera till A:

namespace N1
{
    extern alias N2;

    using A = N2::A;

    class B : A {}
}

slutexempel

Ett extern_alias_directive eller using_alias_directive gör ett alias tillgängligt i en viss kompileringsenhet eller namnområdestext, men det bidrar inte med några nya medlemmar till det underliggande deklarationsutrymmet. Med andra ord är ett aliasdirektiv inte transitivt, utan påverkar snarare bara kompileringsenheten eller namnområdestexten där det inträffar.

Exempel: I följande kod

namespace N3
{
    extern alias R1;

    using R2 = N1.N2;
}

namespace N3
{
    class B : R1::A, R2.I {} // Error, R1 and R2 unknown
}

omfången för de aliasdirektiv som inför R1 och R2 endast omfattar medlemsdeklarationer i namnområdestexten där de finns, så R1 och R2 är okända i den andra namnområdesdeklarationen. Om du placerar aliasdirektiven i den innehållande kompileringsenheten blir aliaset dock tillgängligt i båda namnområdesdeklarationerna:

extern alias R1;

using R2 = N1.N2;

namespace N3
{
    class B : R1::A, R2.I {}
}

namespace N3
{
    class C : R1::A, R2.I {}
}

slutexempel

Varje extern_alias_directive eller using_alias_directive i en compilation_unit eller namespace_body bidrar med ett namn till aliasdeklarationsutrymmet (§7.3) för den omedelbart omslutande compilation_unit eller namespace_body. Aliasdirektivets identifierare ska vara unik inom motsvarande aliasdeklarationsutrymme. Aliasidentifieraren behöver inte vara unik inom det globala deklarationsutrymmet eller deklarationsutrymmet för motsvarande namnområde.

Exempel:

extern alias X;
extern alias Y;

using X = N1.N2; // Error: alias X already exists

class Y {} // Ok

Det använda aliaset med namnet X orsakar ett fel eftersom det redan finns ett alias med namnet X i samma kompileringsenhet. Klassen med namnet Y står inte i konflikt med det externa aliaset med namnet Y eftersom dessa namn läggs till i distinkta deklarationsutrymmen. Det förra läggs till i det globala deklarationsutrymmet och det senare läggs till i aliasdeklarationsutrymmet för den här kompileringsenheten.

När ett aliasnamn matchar namnet på en medlem i ett namnområde ska användningen av något av dessa vara lämpligt kvalificerat:

namespace N1.N2
{
    class B {}
}

namespace N3
{
    class A {}
    class B : A {}
}

namespace N3
{
    using A = N1.N2;
    using B = N1.N2.B;

    class W : B {} // Error: B is ambiguous
    class X : A.B {} // Error: A is ambiguous
    class Y : A::B {} // Ok: uses N1.N2.B
    class Z : N3.B {} // Ok: uses N3.B
}

I den andra namnområdestexten för N3resulterar okvalificerad användning av B ett fel, eftersom N3 innehåller en medlem med namnet B och namnområdestexten som också deklarerar ett alias med namnet B; på samma sätt för A. Klassen N3.B kan refereras till som N3.B eller global::N3.B. Aliaset A kan användas i en kvalificerad aliasmedlem (§14.8), till exempel A::B. Aliaset B är i princip värdelöst. Det kan inte användas i en qualified_alias_member eftersom endast namnområdesalias kan användas i en qualified_alias_member och B alias en typ.

slutexempel

Precis som vanliga medlemmar döljs namn som introduceras av alias_directives av medlemmar med liknande namn i kapslade omfång.

Exempel: I följande kod

using R = N1.N2;

namespace N3
{
    class R {}
    class B: R.A {} // Error, R has no member A
}

referensen till R.A i deklarationen av B orsakar ett kompileringsfel eftersom R refererar till N3.R, inte N1.N2.

slutexempel

Den ordning i vilken extern_alias_directiveskrivs har ingen betydelse. På samma sätt har den ordning i vilken using_alias_directives skrivs ingen betydelse, men alla using_alias_directives ska komma efter alla extern_alias_directives i samma kompileringsenhet eller namnområdestext. Upplösningen av namespace_or_type_name som refereras av en using_alias_directive påverkas inte av själva using_alias_directive eller av andra using_directivei den omedelbart innehållande kompileringsenheten eller namnområdestexten, men kan påverkas av extern_alias_directivei den omedelbart innehållande kompileringsenheten eller namnområdestexten. Med andra ord löses namespace_or_type_name av en using_alias_directive som om den omedelbart innehållande kompileringsenheten eller namnområdestexten inte hade några using_directivemen har rätt uppsättning extern_alias_directives.

Exempel: I följande kod

namespace N1.N2 {}

namespace N3
{
    extern alias X;

    using R1 = X::N; // OK
    using R2 = N1; // OK
    using R3 = N1.N2; // OK
    using R4 = R2.N2; // Error, R2 unknown
}

den senaste using_alias_directive resulterar i ett kompileringsfel eftersom det inte påverkas av föregående using_alias_directive. Den första using_alias_directive resulterar inte i ett fel eftersom omfånget för det externa aliaset X innehåller using_alias_directive.

slutexempel

En using_alias_directive kan skapa ett alias för valfritt namnområde eller typ, inklusive namnområdet där det visas och alla namnområden eller typer som är kapslade i namnområdet.

Åtkomst till ett namnområde eller en typ via ett alias ger exakt samma resultat som åtkomst till namnområdet eller typ via dess deklarerade namn.

Exempel: Givet

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using R1 = N1;
    using R2 = N1.N2;

    class B
    {
        N1.N2.A a; // refers to N1.N2.A
        R1.N2.A b; // refers to N1.N2.A
        R2.A c; // refers to N1.N2.A
    }
}

namnen N1.N2.A, , och R2.A är likvärdiga och alla refererar till klassdeklarationen vars fullständigt kvalificerade namn är N1.N2.AR1.N2.A.

slutexempel

Även om varje del av en partiell typ (§15.2.7) deklareras inom samma namnområde, skrivs delarna vanligtvis inom olika namnområdesdeklarationer. Därför kan olika extern_alias_directives och using_directives finnas för varje del. Vid tolkning av enkla namn (§12.8.4) inom en del anses endast extern_alias_directive s och using_directives i namnområdets organ och kompileringsenhet som omger den delen. Detta kan leda till att samma identifierare har olika betydelser i olika delar.

Exempel:

namespace N
{
    using List = System.Collections.ArrayList;

    partial class A
    {
        List x; // x has type System.Collections.ArrayList
    }
}

namespace N
{
    using List = Widgets.LinkedList;

    partial class A
    {
        List y; // y has type Widgets.LinkedList
    }
}

slutexempel

Om du använder alias kan du namnge en sluten konstruktionstyp, men det går inte att namnge en obundet allmän typdeklaration utan att ange typargument.

Exempel:

namespace N1
{
    class A<T>
    {
        class B {}
    }
}

namespace N2
{
    using W = N1.A;       // Error, cannot name unbound generic type
    using X = N1.A.B;     // Error, cannot name unbound generic type
    using Y = N1.A<int>;  // Ok, can name closed constructed type
    using Z<T> = N1.A<T>; // Error, using alias cannot have type parameters
}

slutexempel

14.5.3 Använda namnområdesdirektiv

En using_namespace_directive importerar de typer som finns i ett namnområde till den omedelbart omslutande kompileringsenheten eller namnområdestexten, vilket gör att identifieraren för varje typ kan användas utan kvalificering.

using_namespace_directive
    : 'using' namespace_name ';'
    ;

I medlemsdeklarationer i en kompileringsenhet eller namnområdestext som innehåller en using_namespace_directive kan de typer som finns i det angivna namnområdet refereras direkt.

Exempel:

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1.N2;

    class B : A {}
}

Ovan, inom medlemsdeklarationer i N3 namnområdet, är typen medlemmar av N1.N2 direkt tillgängliga, och därmed härleds klassen N3.B från klassen N1.N2.A.

slutexempel

En using_namespace_directive importerar de typer som finns i det angivna namnområdet, men importerar inte kapslade namnområden.

Exempel: I följande kod

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1;
    class B : N2.A {} // Error, N2 unknown
}

using_namespace_directive importerar typerna i N1, men inte de namnområden som är kapslade i N1. Referensen till N2.A i deklarationen resulterar B alltså i ett kompileringsfel eftersom inga medlemmar med namnet N2 finns i omfånget.

slutexempel

Till skillnad från en using_alias_directive kan en using_namespace_directive importera typer vars identifierare redan har definierats i den omslutande kompileringsenheten eller namnområdestexten. I själva verket döljs namn som importeras av en using_namespace_directive av medlemmar med liknande namn i den omslutande kompileringsenheten eller namnområdestexten.

Exempel:

namespace N1.N2
{
    class A {}
    class B {}
}

namespace N3
{
    using N1.N2;
    class A {}
}

Här refererar i medlemsdeklarationer i N3 namnområdet A till i stället N1.N2.Aför N3.A .

slutexempel

Eftersom namn kan vara tvetydiga när fler än ett importerat namnområde introducerar samma typnamn är en using_alias_directive användbar för att skilja referensen åt.

Exempel: I följande kod

namespace N1
{
    class A {}
}

namespace N2
{
    class A {}
}

namespace N3
{
    using N1;
    using N2;

    class B : A {} // Error, A is ambiguous
}

både N1 och N2 innehåller en medlem A, och eftersom N3 importer av båda är hänvisningar A i N3 ett kompileringsfel. I den här situationen kan konflikten lösas antingen genom kvalificering av referenser till , eller genom att Ainföra en using_alias_directive som väljer en viss A. Till exempel:

namespace N3
{
    using N1;
    using N2;
    using A = N1.A;

    class B : A {} // A means N1.A
}

slutexempel

Om fler än ett namnområde eller en typ som importerats av using_namespace_directives eller using_static_directives i samma kompileringsenhet eller namnområdestext innehåller typer eller medlemmar med samma namn, betraktas referenser till det namnet som en simple_name tvetydiga.

Exempel:

namespace N1
{
    class A {}
}

class C
{
    public static int A;
}

namespace N2
{
    using N1;
    using static C;

    class B
    {
        void M()
        {
            A a = new A();   // Ok, A is unambiguous as a type-name
            A.Equals(2);     // Error, A is ambiguous as a simple-name
        }
    }
}

N1 innehåller en typmedlem Aoch C innehåller ett statiskt fält A, och eftersom N2 importerar båda, är det tvetydigt att referera till A som en simple_name och ett kompileringsfel.

slutexempel

Precis som en using_alias_directive bidrar inte en using_namespace_directive några nya medlemmar till det underliggande deklarationsutrymmet i kompileringsenheten eller namnområdet, utan påverkar i stället bara kompileringsenheten eller namnområdestexten där den visas.

Den namespace_name som refereras av en using_namespace_directive löses på samma sätt som namespace_or_type_name som refereras av en using_alias_directive. Därför påverkar using_namespace_directivei samma kompileringsenhet eller namnområdestext inte varandra och kan skrivas i valfri ordning.

14.5.4 Användning av statiska direktiv

En using_static_directive importerar kapslade typer och statiska medlemmar som finns direkt i en typdeklaration till den omedelbart omslutande kompileringsenheten eller namnområdestexten, vilket gör det möjligt att använda identifieraren för varje medlem och typ utan kvalificering.

using_static_directive
    : 'using' 'static' type_name ';'
    ;

I medlemsdeklarationer i en kompileringsenhet eller namnområdestext som innehåller en using_static_directive kan tillgängliga kapslade typer och statiska medlemmar (förutom tilläggsmetoder) som finns direkt i deklarationen av den angivna typen refereras direkt.

Exempel:

namespace N1
{
   class A 
   {
        public class B {}
        public static B M() => new B();
   }
}

namespace N2
{
    using static N1.A;

    class C
    {
        void N()
        {
            B b = M();
        }
    }
}

I föregående kod, inom medlemsdeklarationer i N2 namnområdet, är de statiska medlemmarna och kapslade typerna av N1.A direkt tillgängliga, och metoden N kan därför referera till både B och M medlemmar i N1.A.

slutexempel

En using_static_directive importerar inte tilläggsmetoder direkt som statiska metoder, utan gör dem tillgängliga för anrop av tilläggsmetod (§12.8.9.3).

Exempel:

namespace N1 
{
    static class A 
    {
        public static void M(this string s){}
    }
}

namespace N2
{
    using static N1.A;

    class B
    {
        void N()
        {
            M("A");      // Error, M unknown
            "B".M();     // Ok, M known as extension method
            N1.A.M("C"); // Ok, fully qualified
        }
    }
}

using_static_directive importerar tilläggsmetoden M i N1.A, men bara som en tilläggsmetod. Därför resulterar den första referensen i M brödtexten B.N i ett kompileringsfel eftersom inga medlemmar med namnet M finns i omfånget.

slutexempel

En using_static_directive importerar endast medlemmar och typer som deklarerats direkt i den angivna typen, inte medlemmar och typer som deklarerats i basklasser.

Exempel:

namespace N1 
{
    class A 
    {
        public static void M(string s){}
    }

    class B : A
    {
        public static void M2(string s){}
    }
}

namespace N2
{
    using static N1.B;

    class C
    {
        void N()
        {
            M2("B");      // OK, calls B.M2
            M("C");       // Error. M unknown 
        }
    }
}

using_static_directive importerar metoden M2 i N1.B, men importerar inte metoden M i N1.A. Referensen till M i brödtexten C.N i resulterar därför i ett kompileringsfel eftersom inga medlemmar med namnet M finns i omfånget. Utvecklare måste lägga till ett andra using static direktiv för att ange att metoderna i N1.A också ska importeras.

slutexempel

Tvetydigheter mellan flera using_namespace_directives och using_static_directives diskuteras i §14.5.3.

14.6 Medlemsdeklarationer för namnområde

En namespace_member_declaration är antingen en namespace_declaration (§14.3) eller en type_declaration (§14.7).

namespace_member_declaration
    : namespace_declaration
    | type_declaration
    ;

En kompileringsenhet eller en namnområdestext kan innehålla namespace_member_declarations, och sådana deklarationer bidrar med nya medlemmar till det underliggande deklarationsutrymmet för den innehållande kompileringsenheten eller namnområdestexten.

14.7 Typdeklarationer

En type_declaration är en class_declaration (§15.2), en struct_declaration (§16.2), en interface_declaration (§18.2), en enum_declaration (§19.2) eller en delegate_declaration (§20.2).

type_declaration
    : class_declaration
    | struct_declaration
    | interface_declaration
    | enum_declaration
    | delegate_declaration
    ;

En type_declaration kan inträffa som en deklaration på den översta nivån i en kompileringsenhet eller som en medlemsdeklaration inom ett namnområde, en klass eller en struct.

När en typdeklaration för en typ T inträffar som en toppnivådeklaration i en kompileringsenhet är det fullständigt kvalificerade namnet (§7.8.2) av typdeklarationen detsamma som det okvalificerade namnet på deklarationen (§7.8.2). När en typdeklaration för en typ T inträffar inom ett namnområde, en klass eller en structdeklaration, är det fullständigt kvalificerade namnet (§7.8.3) av typdeklarationen S.N, där S är det fullständigt kvalificerade namnet på det innehållande namnområdet, klassen eller structdeklarationen, och N är det okvalificerade namnet på deklarationen.

En typ som deklareras inom en klass eller struct kallas kapslad typ (§15.3.9).

De tillåtna åtkomstmodifierarna och standardåtkomsten för en typdeklaration beror på i vilket sammanhang deklarationen äger rum (§7.5.2):

  • Typer som deklareras i kompileringsenheter eller namnområden kan ha public eller internal komma åt. Standardvärdet är internal åtkomst.
  • Typer som deklareras i klasser kan ha public, protected internal, protected, private protected, internaleller private åtkomst. Standardvärdet är private åtkomst.
  • Typer som deklareras i structs kan ha public, internaleller private åtkomst. Standardvärdet är private åtkomst.

14.8 Kvalificerad aliasmedlem

14.8.1 Allmänt

Namnområdesaliaskvalificeraren :: gör det möjligt att garantera att typnamnsökningar inte påverkas av introduktionen av nya typer och medlemmar. Namnområdesaliaskvalificeraren visas alltid mellan två identifierare som kallas för vänster- och högeridentifierare. Till skillnad från den vanliga . kvalificeraren, letas den vänstra identifieraren för kvalificeringen :: endast upp som extern eller med hjälp av alias.

Ett qualified_alias_member ger explicit åtkomst till det globala namnområdet och till externt eller med hjälp av alias som potentiellt döljs av andra entiteter.

qualified_alias_member
    : identifier '::' identifier type_argument_list?
    ;

En qualified_alias_member kan användas som en namespace_or_type_name (§7.8) eller som vänster operande i en member_access (§12.8.7).

En qualified_alias_member består av två identifierare, så kallade vänster- och högeridentifierare, avgränsade med :: token och eventuellt följt av en type_argument_list. När den vänstra identifieraren är global söks det globala namnområdet efter den högra identifieraren. För andra vänsteridentifierare söks identifieraren upp som extern eller med alias (§14.4 och §14.5.2). Ett kompileringsfel uppstår om det inte finns något sådant alias eller om aliaset refererar till en typ. Om aliaset refererar till ett namnområde söks namnområdet efter den högra identifieraren.

En qualified_alias_member har ett av två formulär:

  • N::I<A₁, ..., Aₑ>, där N och I representerar identifierare och <A₁, ..., Aₑ> är en typargumentlista. (e är alltid minst en.)
  • N::I, där N och I representerar identifierare. (I det här fallet e anses vara noll.)

Med den här notationen bestäms innebörden av en qualified_alias_member på följande sätt:

  • Om N är identifieraren globalsöks Idet globala namnområdet efter :
    • Om det globala namnområdet innehåller ett namnområde med namnet I och e är noll refererar qualified_alias_member till namnområdet.
    • Annars, om det globala namnområdet innehåller en icke-generisk typ med namnet I och e är noll, refererar qualified_alias_member till den typen.
    • Annars, om det globala namnområdet innehåller en typ med namnet I som har e typparametrar, refererar qualified_alias_member till den typen som skapats med de angivna typargumenten.
    • Annars är qualified_alias_member odefinierat och ett kompileringsfel inträffar.
  • Annars, från och med namnområdesdeklarationen (§14.3) som omedelbart innehåller qualified_alias_member (om sådan finns), fortsätter med varje omslutande namnområdesdeklaration (om sådan finns) och slutar med kompileringsenheten som innehåller qualified_alias_member, utvärderas följande steg tills en entitet finns:
    • Om namnområdesdeklarationen eller kompileringsenheten innehåller en using_alias_directive som associerar N med en typ är qualified_alias_member odefinierad och ett kompileringsfel inträffar.
    • Om namnområdesdeklarationen eller kompileringsenheten annars innehåller en extern_alias_directive eller using_alias_directive som associeras N med ett namnområde:
      • Om namnområdet som är associerat med N innehåller ett namnområde med namnet I och e är noll refererar qualified_alias_member till namnområdet.
      • Annars, om namnområdet som är associerat med N innehåller en icke-generisk typ med namnet I och e är noll, refererar qualified_alias_member till den typen.
      • Annars, om namnområdet som är associerat med N innehåller en typ med namnet I som har e typparametrar, refererar qualified_alias_member till den typen som skapats med de angivna typargumenten.
      • Annars är qualified_alias_member odefinierat och ett kompileringsfel inträffar.
  • Annars är qualified_alias_member odefinierat och ett kompileringsfel inträffar.

Exempel: I koden:

using S = System.Net.Sockets;

class A
{
    public static int x;
}

class C
{
    public void F(int A, object S)
    {
        // Use global::A.x instead of A.x
        global::A.x += A;
        // Use S::Socket instead of S.Socket
        S::Socket s = S as S::Socket;
    }
}

-klassen A refereras till och global::A typen System.Net.Sockets.Socket refereras till med S::Socket. Att använda A.x och S.Socket i stället skulle ha orsakat kompileringsfel eftersom A och S skulle ha matchat parametrarna.

slutexempel

Obs! Identifieraren global har endast särskild betydelse när den används som vänsteridentifierare för en qualified_alias_name. Det är inte ett nyckelord och det är inte i sig ett alias. det är ett kontextuellt nyckelord (§6.4.4). I koden:

class A { }

class C
{
    global.A x; // Error: global is not defined
    global::A y; // Valid: References A in the global namespace
}

användning global.A orsakar ett kompileringsfel eftersom det inte finns någon entitet med namnet global i omfånget. Om någon entitet med namnet global fanns i omfånget global skulle in global.A ha matchats till den entiteten.

Att använda global som vänsteridentifierare för en qualified_alias_member alltid orsakar en sökning i global namnområdet, även om det finns ett alias med namnet global. I koden:

using global = MyGlobalTypes;

class A { }

class C 
{
    global.A x; // Valid: References MyGlobalTypes.A
    global::A y; // Valid: References A in the global namespace
}

global.A löser MyGlobalTypes.A till och global::A matchar klassen A i det globala namnområdet.

slutkommentar

14.8.2 Aliasens unika egenskaper

Varje kompileringsenhet och namnområdestext har ett separat deklarationsutrymme för externa alias och med hjälp av alias. Även om namnet på ett externt alias eller ett alias ska vara unikt inom uppsättningen externa alias och använda alias som deklareras i den omedelbart innehållande kompileringsenheten eller namnområdestexten, tillåts ett alias ha samma namn som en typ eller ett namnområde så länge det endast används med :: kvalificeraren.

Exempel: I följande:

namespace N
{
    public class A {}
    public class B {}
}

namespace N
{
    using A = System.IO;

    class X
    {
        A.Stream s1; // Error, A is ambiguous
        A::Stream s2; // Ok
    }
}

namnet A har två möjliga betydelser i den andra namnområdestexten eftersom både klassen A och det använda aliaset A finns i omfånget. Därför är användningen av A i det kvalificerade namnet A.Stream tvetydig och orsakar ett kompileringsfel. Användning av A med kvalificeraren :: är dock inte ett fel eftersom A det endast är ett namnområdesalias.

slutexempel