Sdílet prostřednictvím


14 Oborů názvů

14.1 Obecné

Programy v jazyce C# jsou uspořádány pomocí oborů názvů. Obory názvů se používají jako "interní" organizační systém pro program a jako "externí" organizační systém – způsob prezentace prvků programu, které jsou vystavené jiným programům.

Použití direktiv (§14.5) je poskytováno pro usnadnění používání oborů názvů.

14.2 Jednotky kompilace

Compilation_unit se skládá z nuly nebo více extern_alias_directivenásledovaných nulou nebo více using_directivenásledovanými nulou nebo jednou global_attributes následovanou nulou nebo více namespace_member_declarations. Compilation_unit definuje celkovou strukturu vstupu.

compilation_unit
    : extern_alias_directive* using_directive* global_attributes?
      namespace_member_declaration*
    ;

Program jazyka C# se skládá z jedné nebo více jednotek kompilace. Při kompilaci programu jazyka C# se všechny kompilační jednotky zpracovávají společně. Kompilační jednotky tedy mohou záviset na sobě navzájem, pravděpodobně cyklický.

Extern_alias_directive kompilační jednotky ovlivňují using_directives, global_attributes a namespace_member_declarationtéto kompilační jednotky, ale nemají žádný vliv na jiné kompilační jednotky.

Using_directive kompilační jednotky ovlivňují global_attributes a namespace_member_declarationtéto kompilační jednotky, ale nemají žádný vliv na jiné kompilační jednotky.

Global_attributes (§22.3) kompilační jednotky umožňují specifikaci atributů pro cílové sestavení a modul. Sestavení a moduly fungují jako fyzické kontejnery pro typy. Sestavení se může skládat z několika fyzicky samostatných modulů.

Namespace_member_declaration s každé kompilační jednotky programu přispívají členy do jediného prostoru deklarace nazývaného globální obor názvů.

Příklad:

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

Tyto dvě kompilační jednotky přispívají k jednomu globálnímu oboru názvů, v tomto případě deklarují dvě třídy s plně kvalifikovanými názvy A a B. Vzhledem k tomu, že tyto dvě kompilační jednotky přispívají ke stejnému prostoru deklarace, byla by chyba, pokud by každá obsahovala deklaraci člena se stejným názvem.

end example

14.3 Deklarace oboru názvů

Namespace_declaration se skládá z oboru názvů klíčových slov, za kterým následuje název oboru názvů a text, volitelně následovaný středníkem.

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

qualified_identifier
    : identifier ('.' identifier)*
    ;

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

K namespace_declaration může dojít jako deklarace nejvyšší úrovně v compilation_unit nebo jako deklarace člena v rámci jiného namespace_declaration. Když namespace_declaration dojde v compilation_unit jako deklarace nejvyšší úrovně, obor názvů se stane členem globálního oboru názvů. Když dojde namespace_declaration v rámci jiného namespace_declaration, vnitřní obor názvů se stane členem vnějšího oboru názvů. V obou případech musí být název oboru názvů jedinečný v rámci obsahujícího oboru názvů.

Obory názvů jsou implicitně public a deklarace oboru názvů nemůže obsahovat žádné modifikátory přístupu.

V rámci namespace_body volitelná using_directivenaimportují názvy jiných oborů názvů, typů a členů, které umožňují odkazovat přímo místo kvalifikovaných názvů. Volitelné namespace_member_declarationpřispívají členy do prostoru deklarace oboru názvů. Všimněte si, že všechny using_directivese zobrazí před každou prohlášeními o členech.

Qualified_identifier namespace_declaration může být jeden identifikátor nebo posloupnost identifikátorů oddělených tokeny ".". Druhý formulář umožňuje programu definovat vnořený obor názvů bez lexikálního vnoření několika deklarací oboru názvů.

Příklad:

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

je sémanticky ekvivalentní

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

end example

Obory názvů jsou otevřené a dvě deklarace oboru názvů se stejným plně kvalifikovaným názvem (§7.8.2) přispívají do stejného prostoru deklarace (§7.3).

Příklad: V následujícím kódu

namespace N1.N2
{
    class A {}
}

namespace N1.N2
{
    class B {}
}

dvě deklarace oboru názvů výše přispívají ke stejnému prostoru deklarace, v tomto případě deklarují dvě třídy s plně kvalifikovanými názvy N1.N2.A a N1.N2.B. Vzhledem k tomu, že dvě deklarace přispívají ke stejnému prostoru deklarace, byla by chyba, pokud každá deklarace člena se stejným názvem.

end example

14.4 Direktivy extern aliasů

Extern_alias_directive zavádí identifikátor, který slouží jako alias oboru názvů. Specifikace aliasovaného oboru názvů je externí pro zdrojový kód programu a vztahuje se také na vnořené obory názvů aliasovaného oboru názvů.

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

Rozsah extern_alias_directive se vztahuje na using_directive, global_attributes a namespace_member_declarationjeho bezprostředně obsahující compilation_unit nebo namespace_body.

V rámci kompilační jednotky nebo těla oboru názvů, který obsahuje extern_alias_directive, lze identifikátor zavedený extern_alias_directive použít k odkazování na aliasovaný obor názvů. Jedná se o chybu v době kompilace, aby identifikátor byl slovo global.

Alias představený extern_alias_directive je velmi podobný aliasu zavedenému using_alias_directive. Podrobnější informace o extern_alias_directives a using_alias_directives naleznete v §14.5.2.

alias je kontextové klíčové slovo (§6.4.4) a má zvláštní význam pouze tehdy, když bezprostředně následuje extern klíčové slovo v extern_alias_directive.

K chybě dojde, pokud program deklaruje extern alias, pro který není k dispozici žádná externí definice.

Příklad: Následující program deklaruje a používá dva extern aliasy a YX každý z nich představuje kořen jedinečné hierarchie oborů názvů:

extern alias X;
extern alias Y;

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

Program deklaruje existenci extern aliasů X a Y, ale skutečné definice aliasů jsou pro program vnější. Identické pojmenované N.B třídy lze nyní odkazovat jako X.N.B a Y.N.B, nebo pomocí kvalifikátor X::N.B aliasu oboru názvů a Y::N.B. end example

14.5 Použití direktiv

14.5.1 Obecné

Použití direktiv usnadňuje použití oborů názvů a typů definovaných v jiných oborech názvů. Použití direktiv ovlivňuje proces překladu názvů namespace_or_type_names (§7.8) a simple_names (§12.8.4), ale na rozdíl od deklarací using_directivenepřispívá novým členům do podkladových prostorů deklarací jednotek kompilace nebo oborů názvů, ve kterých se používají.

using_directive
    : using_alias_directive
    | using_namespace_directive
    | using_static_directive    
    ;

Using_alias_directive (§14.5.2) zavádí alias oboru názvů nebo typu.

A using_namespace_directive (§14.5.3) importuje členy typu oboru názvů.

A using_static_directive (§14.5.4) importuje vnořené typy a statické členy typu.

Rozsah using_directive se vztahuje na namespace_member_declarations jeho bezprostředně obsahující kompilační jednotku nebo tělo oboru názvů. Rozsah using_directive konkrétně nezahrnuje jeho partnerský using_directive s. Peer using_directivese tedy navzájem neovlivňují a pořadí, ve kterém jsou napsány, je zanedbatelné. Naproti tomu rozsah extern_alias_directive zahrnuje using_directivedefinované ve stejné jednotce kompilace nebo oboru názvů.

14.5.2 Použití direktiv aliasů

Using_alias_directive zavádí identifikátor, který slouží jako alias oboru názvů nebo typu v rámci bezprostředně ohraničující kompilační jednotku nebo tělo oboru názvů.

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

V rámci globálních atributů a deklarací členů v kompilační jednotce nebo těle oboru názvů, který obsahuje using_alias_directive, lze identifikátor zavedený using_alias_directive použít k odkazování na daný obor názvů nebo typ.

Příklad:

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

    class B: A {}
}

Výše v rámci deklarací členů v oboru názvů A je alias pro N1.N2.A, a proto třída N3.B odvozena od třídy N1.N2.A.N3 Stejný účinek lze získat vytvořením aliasu R pro N1.N2 a následným odkazem R.A:

namespace N3
{
    using R = N1.N2;

    class B : R.A {}
}

end example

V rámci direktiv using lze globální atributy a deklarace členů v jednotce kompilace nebo těle oboru názvů, které obsahují extern_alias_directive, identifikátor zavedený extern_alias_directive použít k odkazování na přidružený obor názvů.

Příklad: Příklad:

namespace N1
{
    extern alias N2;

    class B : N2::A {}
}

Výše je v rámci deklarací členů v N1 oboru názvů alias pro určitý obor názvů, N2 jehož definice je externí ke zdrojovému kódu programu. Třída N1.B je odvozena od třídy N2.A. Stejný účinek lze získat vytvořením aliasu A pro N2.A a následným odkazem A:

namespace N1
{
    extern alias N2;

    using A = N2::A;

    class B : A {}
}

end example

Extern_alias_directive nebo using_alias_directive zpřístupňuje alias v rámci konkrétní jednotky kompilace nebo těla oboru názvů, ale nepřispívá do podkladového prostoru deklarace žádné nové členy. Jinými slovy, direktiva aliasu není tranzitivní, ale spíše ovlivňuje pouze kompilační jednotku nebo tělo oboru názvů, ve kterém se vyskytuje.

Příklad: V následujícím kódu

namespace N3
{
    extern alias R1;

    using R2 = N1.N2;
}

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

obory direktiv aliasů, které zavádějí R1 a R2 rozšiřují pouze na deklarace členů v těle oboru názvů, ve kterém jsou obsaženy, takže R1 a R2 jsou neznámé ve druhé deklaraci oboru názvů. Umístění direktiv aliasů do obsahující kompilační jednotky však způsobí, že alias bude k dispozici v rámci obou deklarací oboru názvů:

extern alias R1;

using R2 = N1.N2;

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

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

end example

Každý extern_alias_directive nebo using_alias_directive v compilation_unit nebo namespace_body přispívá názvem do prostoru deklarace aliasu (§7.3) bezprostředně uzavřeného compilation_unit nebo namespace_body. Identifikátor směrnice aliasu musí být jedinečný v rámci odpovídajícího prostoru deklarace aliasu. Identifikátor aliasu nemusí být jedinečný v rámci globálního prostoru deklarace nebo prostoru deklarace odpovídajícího oboru názvů.

Příklad:

extern alias X;
extern alias Y;

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

class Y {} // Ok

Použití pojmenovaného X aliasu způsobí chybu, protože už existuje alias pojmenovaný X ve stejné jednotce kompilace. Pojmenovaná třída Y není v konfliktu s externím aliasem pojmenovaným Y , protože tyto názvy jsou přidány do odlišných prostorů deklarací. První se přidá do globálního prostoru deklarace a druhý se přidá do prostoru deklarace aliasu pro tuto kompilační jednotku.

Pokud název aliasu odpovídá názvu člena oboru názvů, musí být použití některého z těchto názvů odpovídajícím způsobem kvalifikované:

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
}

Ve druhém těle oboru názvů pro N3nekvalifikované použití B výsledků v důsledku chyby, protože N3 obsahuje člen pojmenovaný B a tělo oboru názvů, které také deklaruje alias s názvem B; podobně pro A. Na třídu N3.B lze odkazovat jako N3.B nebo global::N3.B. Alias A lze použít v kvalifikovaném členu aliasu (§14.8), například A::B. Alias B je v podstatě zbytečný. Nelze jej použít v qualified_alias_member , protože v qualified_alias_member a B aliasech typu je možné použít pouze aliasy oboru názvů.

end example

Stejně jako běžné členy jsou názvy zavedené alias_directives skryté podobnými pojmenovanými členy v vnořených oborech.

Příklad: V následujícím kódu

using R = N1.N2;

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

odkaz na R.A deklaraci příčin chyby v době kompilace, protože R odkazuje na N3.R, nikoli N1.N2B .

end example

Pořadí, ve kterém jsou zapsány extern_alias_directive, nemá žádný význam. Pořadí, ve kterém jsou zapsány using_alias_directives, nemá žádný význam, ale všechny using_alias_directives po všech extern_alias_directive ve stejné kompilačníjednotce nebo názvovém prostoru. Řešení namespace_or_type_name odkazovaných using_alias_directive není ovlivněno samotným using_alias_directive nebo jinými using_directivev bezprostředně obsahujícím kompilační jednotku nebo tělo oboru názvů, ale může být ovlivněno extern_alias_directives v bezprostředně obsahující kompilační jednotce nebo těle oboru názvů. Jinými slovy, namespace_or_type_name using_alias_directive se vyřeší, jako by bezprostředně obsahující kompilační jednotku nebo tělo oboru názvů nemělo žádné using_directives, ale má správnou sadu extern_alias_directives.

Příklad: V následujícím kódu

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
}

poslední using_alias_directive způsobí chybu v době kompilace, protože předchozí using_alias_directive to neovlivní. První using_alias_directive nemá za následek chybu, protože rozsah externího aliasu X zahrnuje using_alias_directive.

end example

Using_alias_directive může vytvořit alias pro libovolný obor názvů nebo typ, včetně oboru názvů, ve kterém se zobrazí, a libovolného oboru názvů nebo typu vnořeného v daném oboru názvů.

Přístup k oboru názvů nebo typu prostřednictvím aliasu poskytuje přesně stejný výsledek jako přístup k danému oboru názvů nebo typu prostřednictvím deklarovaného názvu.

Příklad: Dané

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
    }
}

názvy N1.N2.A, R1.N2.Aa R2.A jsou ekvivalentní a všechny odkazují na deklaraci třídy, jejíž plně kvalifikovaný název je N1.N2.A.

end example

I když je každá část částečného typu (§15.2.7) deklarována ve stejném oboru názvů, části se obvykle zapisují do různých deklarací oboru názvů. Proto mohou být pro každou část přítomny různé extern_alias_directives a using_directive. Při interpretaci jednoduchých názvů (§12.8.4) v rámci jedné části se považují pouze extern_alias_directives a using_directives těl oboru názvů a kompilační jednotky ohraničující tuto část. To může mít za následek, že stejný identifikátor má různé významy v různých částech.

Příklad:

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
    }
}

end example

Použití aliasů může pojmenovat uzavřený vytvořený typ, ale nemůže pojmenovat nevázanou deklaraci obecného typu bez zadání argumentů typu.

Příklad:

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
}

end example

14.5.3 Použití direktiv oborů názvů

Using_namespace_directive importuje typy obsažené v oboru názvů do bezprostředně uzavřené kompilační jednotky nebo těla oboru názvů, což umožňuje použít identifikátor každého typu bez kvalifikace.

using_namespace_directive
    : 'using' namespace_name ';'
    ;

V rámci deklarací členů v kompilační jednotce nebo těle oboru názvů, který obsahuje using_namespace_directive, lze odkazovat přímo na typy obsažené v daném oboru názvů.

Příklad:

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1.N2;

    class B : A {}
}

Výše v rámci deklarací členů v N3 oboru názvů jsou členy N1.N2 typu přímo k dispozici, a proto třída N3.B je odvozena od třídy N1.N2.A.

end example

Using_namespace_directive importuje typy obsažené v daném oboru názvů, ale konkrétně neimportuje vnořené obory názvů.

Příklad: V následujícím kódu

namespace N1.N2
{
    class A {}
}

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

using_namespace_directive importuje typy obsažené v N1, ale ne obory názvů vnořené do N1. Odkaz na N2.A deklaraci B výsledků tedy způsobí chybu v době kompilace, protože žádné členy pojmenované N2 nejsou v oboru.

end example

Na rozdíl od using_alias_directive může using_namespace_directive importovat typy, jejichž identifikátory jsou již definovány v rámci nadřazené kompilační jednotky nebo těla oboru názvů. V důsledku toho jsou názvy importované using_namespace_directive skryty podobnými pojmenovanými členy v nadřazené jednotce kompilace nebo textu oboru názvů.

Příklad:

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

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

Zde v rámci deklarací členů v N3 oboru názvů A odkazuje N3.A spíše než N1.N2.Ana .

end example

Vzhledem k tomu, že názvy můžou být nejednoznačné, když více než jeden importovaný obor názvů zavádí stejný název typu, je using_alias_directive užitečné k nejednoznačnosti odkazu.

Příklad: V následujícím kódu

namespace N1
{
    class A {}
}

namespace N2
{
    class A {}
}

namespace N3
{
    using N1;
    using N2;

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

a N1 N2 obsahují člena Aa protože N3 importuje obojí, odkazování A v N3 je chyba v době kompilace. V této situaci lze konflikt vyřešit buď prostřednictvím kvalifikace odkazů na A, nebo zavedením using_alias_directive , který vybere konkrétní A. Příklad:

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

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

end example

Kromě toho platí, že pokud více než jeden obor názvů nebo typ importovaný using_namespace_directives nebo using_static_directiveve stejné jednotce kompilace nebo těle oboru názvů obsahují typy nebo členy se stejným názvem, odkazy na tento název jako simple_name jsou považovány za nejednoznačné.

Příklad:

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 obsahuje člen Atypu a C obsahuje statické pole Aa protože N2 importuje obojí, odkazování A jako simple_name je nejednoznačné a chyba v době kompilace.

end example

Podobně jako using_alias_directive using_namespace_directive nepřispívá žádné nové členy do podkladového prostoru deklarace kompilační jednotky nebo oboru názvů, ale ovlivňuje pouze kompilační jednotku nebo tělo oboru názvů, ve kterém se zobrazuje.

Namespace_name odkazovaná using_namespace_directive se vyřeší stejným způsobem jako namespace_or_type_name odkazovaná using_alias_directive. Proto using_namespace_directives ve stejné kompilační jednotce nebo těle oboru názvů nemají vliv na sebe a lze je zapsat v libovolném pořadí.

14.5.4 Použití statických direktiv

Using_static_directive importuje vnořené typy a statické členy obsažené přímo v deklaraci typu do bezprostředně uzavřené kompilační jednotky nebo těla oboru názvů, což umožňuje použít identifikátor každého člena a typu bez kvalifikace.

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

V rámci deklarací členů v kompilační jednotce nebo těle oboru názvů, který obsahuje using_static_directive, lze přímo odkazovat na přístupné vnořené typy a statické členy (s výjimkou rozšiřujících metod) obsažené přímo v deklaraci daného typu.

Příklad:

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();
        }
    }
}

V předchozím kódu jsou v rámci deklarací členů v N2 oboru názvů statické členy a vnořené typy N1.A přímo k dispozici, a proto metoda N může odkazovat jak na B M členy N1.A.

end example

Using_static_directive konkrétně neimportuje rozšiřující metody přímo jako statické metody, ale zpřístupňuje je pro vyvolání rozšiřující metody (§12.8.9.3).

Příklad:

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 importuje rozšiřující metodu M obsaženou v N1.A, ale pouze jako rozšiřující metodu. Proto první odkaz na M text B.N výsledků v době kompilace chyba, protože žádné členy pojmenované M nejsou v oboru.

end example

Using_static_directive importuje pouze členy a typy deklarované přímo v daném typu, nikoli členy a typy deklarované v základních třídách.

Příklad:

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 importuje metodu M2 obsaženou v N1.B, ale nenaimportuje metodu M obsaženou v N1.A. Proto odkaz na M text C.N výsledků v době kompilace chyba, protože žádné členy pojmenované M nejsou v oboru. Vývojáři musí přidat druhou using static direktivu, aby určili, že se mají importovat i metody N1.A .

end example

Nejednoznačnosti mezi více using_namespace_directives a using_static_directives jsou popsány v §14.5.3.

14.6 Deklarace členů oboru názvů

Namespace_member_declaration je namespace_declaration (§14.3) nebo type_declaration (§14.7).

namespace_member_declaration
    : namespace_declaration
    | type_declaration
    ;

Kompilační jednotka nebo tělo oboru názvů může obsahovat namespace_member_declarations a tyto deklarace přispívají novým členům do podkladového prostoru deklarace obsahující kompilační jednotky nebo těla oboru názvů.

14.7 Deklarace typů

Type_declaration je class_declaration (§15.2), struct_declaration (§16.2), interface_declaration (§18.2), enum_declaration (§19.2) nebo delegate_declaration (§20.2).

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

K type_declaration může dojít jako deklarace nejvyšší úrovně v kompilační jednotce nebo jako deklarace člena v rámci oboru názvů, třídy nebo struktury.

Pokud deklarace typu pro typ T nastane jako deklarace nejvyšší úrovně v kompilační jednotce, plně kvalifikovaný název (§7.8.2) deklarace typu je stejný jako nekvalifikovaný název deklarace (§7.8.2). Pokud deklarace typu pro typ T nastane v rámci deklarace oboru názvů, třídy nebo struktury, plně kvalifikovaný název (§7.8.3) deklarace S.Ntypu , kde S je plně kvalifikovaný název obsahující obor názvů, třídy nebo deklarace struktury a N je nekvalifikovaný název deklarace.

Typ deklarovaný v rámci třídy nebo struktury se nazývá vnořený typ (§15.3.9).

Povolené modifikátory přístupu a výchozí přístup pro deklaraci typu závisí na kontextu, ve kterém se deklarace provádí (§7.5.2):

  • Typy deklarované v jednotkách kompilace nebo oborech názvů mohou mít public nebo internal mají přístup. Výchozí hodnota je internal přístup.
  • Typy deklarované ve třídách mohou mít public, , protected internalprotected, private protected, , internal, nebo private přístup. Výchozí hodnota je private přístup.
  • Typy deklarované ve strukturách mohou mít public, internalnebo private přístup. Výchozí hodnota je private přístup.

14.8 Kvalifikovaný člen aliasu

14.8.1 Obecné

Kvalifikátor :: aliasu oboru názvů umožňuje zaručit, že vyhledávání názvů typů není ovlivněno zavedením nových typů a členů. Kvalifikátor aliasu oboru názvů se vždy zobrazuje mezi dvěma identifikátory, které se označují jako identifikátory vlevo a zprava. Na rozdíl od běžného . kvalifikátoru se levý identifikátor kvalifikátoru :: vyhledá pouze jako extern nebo pomocí aliasu.

Qualified_alias_member poskytuje explicitní přístup ke globálnímu oboru názvů a externímu oboru názvů nebo použití aliasů, které jsou potenciálně skryté jinými entitami.

qualified_alias_member
    : identifier '::' identifier type_argument_list?
    ;

Qualified_alias_member lze použít jako namespace_or_type_name (§7.8) nebo jako levý operand v member_access (§12.8.7).

Qualified_alias_member se skládá ze dvou identifikátorů, označovaných jako identifikátory zleva a zprava, které jsou označeny tokenem::, a volitelně následuje type_argument_list. Pokud je identifikátor vlevo globální, globální obor názvů se vyhledá pro identifikátor pravé ruky. U jakéhokoli jiného levého identifikátoru se tento identifikátor vyhledá jako extern nebo používá alias (§14.4 a §14.5.2). K chybě v době kompilace dochází v případě, že neexistuje žádný takový alias nebo alias odkazuje na typ. Pokud alias odkazuje na obor názvů, vyhledá se v daném oboru názvů pravý identifikátor.

Qualified_alias_member má jednu ze dvou forem:

  • N::I<A₁, ..., Aₑ>, kde N a I představuje identifikátory a <A₁, ..., Aₑ> je seznam argumentů typu. (e je vždy alespoň jedna.)
  • N::I, kde N a I představuje identifikátory. (V tomto případě e se považuje za nulu.)

Při tomto zápisu je význam qualified_alias_member určen takto:

  • Pokud N se jedná o identifikátor global, vyhledá se Iglobální obor názvů:
    • Pokud globální obor názvů obsahuje obor názvů s názvem I nula e , qualified_alias_member odkazuje na tento obor názvů.
    • V opačném případě, pokud globální obor názvů obsahuje ne generický typ pojmenovaný I a e je nula, qualified_alias_member odkazuje na tento typ.
    • Pokud globální obor názvů obsahuje typ s názvem I e s parametry typu, qualified_alias_member odkazuje na tento typ vytvořený s danými argumenty typu.
    • V opačném případě je qualified_alias_member nedefinovaný a dojde k chybě v době kompilace.
  • Jinak počínaje prohlášením oboru názvů (§14.3) bezprostředně obsahujícím qualified_alias_member (pokud existuje), pokračujte každou uzavřenou deklarací oboru názvů (pokud existuje) a končící jednotkou kompilace obsahující qualified_alias_member, následující kroky se vyhodnocují, dokud se nenachází entita:
    • Pokud deklarace oboru názvů nebo kompilační jednotka obsahuje using_alias_directive , která přidruží N k typu, není definována qualified_alias_member a dojde k chybě v době kompilace.
    • Jinak pokud deklarace oboru názvů nebo kompilační jednotka obsahuje extern_alias_directive nebo using_alias_directive , které přidruží N k oboru názvů, pak:
      • Pokud obor názvů přidružený N obsahuje název I oboru názvů a e je nula, qualified_alias_member odkazuje na tento obor názvů.
      • V opačném případě, pokud obor názvů přidružený N obsahuje ne generický typ pojmenovaný I a e je nula, qualified_alias_member odkazuje na tento typ.
      • Jinak pokud obor názvů přidružený N obsahuje typ s názvem I s e parametry typu, qualified_alias_member odkazuje na tento typ vytvořený s danými argumenty typu.
      • V opačném případě je qualified_alias_member nedefinovaný a dojde k chybě v době kompilace.
  • V opačném případě je qualified_alias_member nedefinovaný a dojde k chybě v době kompilace.

Příklad: V kódu:

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;
    }
}

třída A je odkazována s global::A a typ System.Net.Sockets.Socket je odkazován s S::Socket. Použití A.x a S.Socket místo toho by způsobilo chyby v době kompilace, protože A by S se vyřešily parametry.

end example

Poznámka: Identifikátor global má zvláštní význam pouze v případech, kdy se používá jako levý identifikátor qualified_alias_name. Není to klíčové slovo a není to sám alias; je kontextové klíčové slovo (§6.4.4). V kódu:

class A { }

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

použití global.A způsobí chybu v době kompilace, protože v oboru neexistuje žádná entita global . Pokud by některá entita s názvem global byla v oboru, přeložila global global.A by se na tuto entitu.

Použití global jako identifikátoru levé strany qualified_alias_member vždy způsobí vyhledávání v global oboru názvů, i když existuje alias s názvem global. V kódu:

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 překládá a MyGlobalTypes.A global::A překládá na třídu A v globálním oboru názvů.

koncová poznámka

14.8.2 Jedinečnost aliasů

Každá jednotka kompilace a tělo oboru názvů má samostatný prostor deklarace pro extern aliasy a použití aliasů. I když je název externího aliasu nebo použití aliasu jedinečný v rámci sady externích aliasů a použití aliasů deklarovaných v bezprostředně obsahující kompilační jednotce nebo těle oboru názvů, může mít alias stejný název jako typ nebo obor názvů, pokud se používá pouze s kvalifikátorem :: .

Příklad: V následujícím příkladu:

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
    }
}

název A má ve druhém těle oboru názvů dva možné významy, protože A třída i alias A using jsou v oboru. Z tohoto důvodu je použití A v kvalifikovaném názvu A.Stream nejednoznačné a způsobuje chybu v době kompilace. Použití A s kvalifikátorem :: však není chybou, protože A se vyhledá pouze jako alias oboru názvů.

end example