14 Névterek

14.1 Általános

A C#-programok névterek használatával vannak rendszerezve. A névterek mind a programok "belső" szervezeti rendszereként, mind pedig "külső" szervezeti rendszerként használatosak – ez a más programok számára elérhető programelemek bemutatásának módja.

A névterek használatának megkönnyítése érdekében irányelveket (14.6. §) és globális irányelveket (14.5. §) kell alkalmazni.

14.2 Fordítási egységek

A compilation_unit nullából vagy több extern_alias_directive, majd nullából vagy több global_using_directives-ből, majd nullából vagy több using_directives-ből, majd nullából vagy egy global_attributes , majd egy compilation_unit_body áll. A compilation_unit_body lehet nulla vagy több statement_list, majd nulla vagy több namespace_member_declarations, vagy file_scoped_namespace_declaration. A compilation_unit határozza meg a bemenet általános szerkezetét.

compilation_unit
    : extern_alias_directive* using_directive* global_attributes? compilation_unit_body
    ;

compilation_unit_body
    : statement_list* namespace_member_declaration*
    | file_scoped_namespace_declaration
    ;

A C#-programok egy vagy több fordítási egységből állnak. Egy C#-program fordításakor az összes fordítási egység együtt lesz feldolgozva. Így a fordítási egységek egymástól függhetnek, esetleg körkörös módon.

A fordítási egység extern_alias_directives-i hatással vannak a fordítási egység global_using_directive, using_directives, global_attributes és compilation_unit_body , de nincs hatással más fordítási egységekre.

A fordítási egység using_directiveglobal_attributes éscompilation_unit_body befolyásolják, de nincs hatással más fordítási egységekre.

A fordítási egység global_using_directivea program összes fordítási egységének global_attributes és namespace_member_declarations-jét érinti.

A fordítási egység global_attributes (23.3. §) lehetővé teszi a célszerelvény és modul attribútumainak specifikációját. A szerelvények és modulok fizikai tárolóként működnek a típusok esetében. Egy szerelvény több fizikailag különálló modulból állhat.

A program egyes fordítási egységeinek namespace_member_declarationvagy file_scoped_namespace_declaration a tagok egy globális névtér nevű egyetlen deklarációs térhez járulnak hozzá.

A file_scoped_namespace_declaration a szemantikailag egyenértékű namespace_declaration megfelelő tagok közreműködésével (14.3. §).

Example:

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

A két fordítási egység hozzájárul az egyetlen globális névtérhez, ebben az esetben két osztályt deklarál a teljes névvel A és B. Mivel a két összeállítási egység ugyanahhoz a deklarációs területhez járul hozzá, hiba lett volna, ha mindegyik egy azonos nevű tag deklarációját tartalmazza.

záró példa

14.3 Névtér deklarációk

A namespace_declaration a kulcsszó névteréből, majd egy névtérnévből és egy törzsből állnak, amelyet igény szerint pontosvessző követ. A file_scoped_namespace_declaration a kulcsszóból namespace, majd egy névtérnévből, pontosvesszőből és extern_alias_directives, using_directives és type_declarationválasztható listájából állnak.

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

file_scoped_namespace_declaration
    : 'namespace' qualified_identifier ';' extern_alias_directive* using_directive*
      type_declaration*
    ;

qualified_identifier
    : identifier ('.' identifier)*
    ;

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

A namespace_declaration egy compilation_unit legfelső szintű deklarációjaként vagy egy másik namespace_declaration belüli tagi deklarációként is előfordulhat. Ha egy namespace_declaration egy compilation_unit legfelső szintű deklarációjaként történik, a névtér a globális névtér tagjává válik. Ha egy namespace_declaration egy másik namespace_declaration belül történik, a belső névtér a külső névtér tagjává válik. A névtér nevének mindkét esetben egyedinek kell lennie az azt tartalmazó névtéren belül.

A file_scoped_namespace_declaration csak legfelső szintű deklarációként fordulhat elő egy compilation_unit. Így a deklarált névtér a globális névtér tagjává válik.

A névterek implicitek public , és a névtér deklarációja nem tartalmazhat hozzáférési módosítókat.

Egy namespace_body belül az opcionális using_directivemás névterek, típusok és tagok nevét importálják, így közvetlenül hivatkozhatnak rájuk a minősített nevek helyett. A választható namespace_member_declarationtagokat a névtér deklarációs területéhez. Vegye figyelembe, hogy minden using_directivemeg kell jelennie a tagi nyilatkozatok előtt.

Egy file_scoped_namespace_declaration az opcionális using_directiveimportálják az egyéb névterek, típusok és tagok nevét, így közvetlenül hivatkozhatnak rájuk a minősített nevek helyett. Az opcionális type_declarationtagokat a névtér deklarációs területéhez. Vegye figyelembe, hogy minden using_directivemeg kell jelennie a típusdeklarációk előtt.

Egy namespace_declaration és file_scoped_namespace_declaration qualified_identifier lehet egyetlen azonosító vagy azonosítósorozat, amelyet "." jogkivonatok választanak el. Az utóbbi űrlap lehetővé teszi, hogy a program több névtérdeklaráció lexikális beágyazása nélkül definiáljon beágyazott névteret.

Example:

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

szemantikailag egyenértékű a

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

záró példa

A file_scoped_namespace_declaration lehetővé teszi, hogy a névtér-deklarációt kísérő { … } blokk nélkül lehessen megírni.

Example:

namespace Name;
using System;
class C
{
}

szemantikailag egyenértékű a

namespace Name
{
    using System;
    class C
    {
    }
}

záró példa

A file_scoped_namespace_declaration ugyanazzal a namespace_declaration kezeli a compilation_unit ugyanazon a helyen, ugyanazzal a qualified_identifier. A file_scoped_namespace_declaration extern_alias_directives, using_directives és type_declarations-e úgy viselkednek, mintha ugyanabban a sorrendben deklarálták volna őket az namespace_declaration namespace_body belül.

Megjegyzés: A nyelvtani meghatározásnak megfelelően a fordítási egység nem tartalmazhat file_scoped_namespace_declaration és namespace_declaration. Nem tartalmazhat több file_scoped_namespace_declarations-t. Nem tartalmazhat file_scoped_namespace_declaration és legfelső szintű utasításokatis. type_declarations nem előzhet meg file_scoped_namespace_declaration. végjegyzet

A különböző fordítási egységek a namespace_member_declaration vagy file_scoped_namespace_declaration szintaxissal is hozzájárulhatnak ugyanahhoz a névtérhez.

A névterek nyitott végűek, és két azonos teljes névvel rendelkező névtér-deklaráció (7.8.3. §) járul hozzá ugyanahhoz a deklarációs térhez (7.3. §).

Példa: Az alábbi kódban

namespace N1.N2
{
    class A {}
}

namespace N1.N2
{
    class B {}
}

a fenti két névtér-deklaráció ugyanahhoz a deklarációs térhez járul hozzá, ebben az esetben két osztályt deklarál a teljes névvel N1.N2.A és N1.N2.B. Mivel a két deklaráció ugyanahhoz a deklarációs térhez járul hozzá, hiba lett volna, ha mindegyik egy azonos nevű tag deklarációját tartalmazza.

záró példa

A file_scoped_namespace_declaration lehetővé teszi, hogy a névtér-deklarációt kísérő { … } blokk nélkül lehessen megírni.

Example:

namespace Name;
using System;
class C
{
}

szemantikailag egyenértékű a

namespace Name
{
    using System;
    class C
    {
    }
}

záró példa

A file_scoped_namespace_declaration ugyanazzal a namespace_declaration kezeli a compilation_unit ugyanazon a helyen, ugyanazzal a qualified_identifier. A file_scoped_namespace_declaration extern_alias_directives, using_directives és type_declarations-e úgy viselkednek, mintha ugyanabban a sorrendben deklarálták volna őket az namespace_declaration namespace_body belül.

Megjegyzés: A nyelvtani meghatározásnak megfelelően a fordítási egység nem tartalmazhat file_scoped_namespace_declaration és namespace_declaration. Nem tartalmazhat több file_scoped_namespace_declarations-t. Nem tartalmazhat file_scoped_namespace_declaration és legfelső szintű utasításokatis. type_declarations nem előzhet meg file_scoped_namespace_declaration. végjegyzet

A különböző fordítási egységek a namespace_member_declaration vagy file_scoped_namespace_declaration szintaxissal is hozzájárulhatnak ugyanahhoz a névtérhez.

14.4 Extern alias irányelvek

Egy extern_alias_directive egy névtér aliasaként szolgáló azonosítót vezet be. Az aliasos névtér specifikációja kívül esik a program forráskódán, és az aliasos névtér beágyazott névtereire is vonatkozik.

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

A extern_alias_directive hatókörét a 7.7.1.

Egy extern_alias_directive tartalmazó összeállítási egységben vagy névtértörzsben a extern_alias_directive által bevezetett azonosító használható az aliasos névtérre való hivatkozáshoz. Fordítási időhiba, hogy az azonosító legyen a szó global.

A extern_alias_directive által bevezetett alias nagyon hasonlít a using_alias_directive által bevezetett aliashoz. Az extern_alias_directives és using_alias_directiverészletesebb ismertetését a 14.6.2.

aliasegy környezetfüggő kulcsszó (6.4.4.4. §), és csak akkor van különleges jelentése, ha azonnal követi a extern egy extern_alias_directive.

Hiba akkor fordul elő, ha egy program olyan extern aliast deklarál, amelyhez nincs megadva külső definíció.

Példa: A következő program két extern aliast deklarál és használ, X amelyek Ymindegyike egy különálló névtérhierarchia gyökerét jelöli:

extern alias X;
extern alias Y;

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

A program deklarálja a kiirtott aliasok X meglétét, de Yaz aliasok tényleges definíciói külsőek a programon. A névtér alias-minősítője és N.Ba névtér aliasának minősítőjeként X.N.BY.N.B és néven hivatkozhat X::N.B az azonos nevű Y::N.B osztályokra. záró példa

14.5 Globális irányelvek

14.5.1 Általános

A globális használatról szóló irányelv a fordítási egység legfelső szintjén lévő, használatban lévő irányelv (14.6. §).

global_using_directive
    : global_using_alias_directive
    | global_using_namespace_directive
    | global_using_static_directive
    ;

Megjegyzés: A global_using_directive hatóköre a program összes fordítási egységének namespace_member_declarations-jára terjed ki. A global_using_directive hatóköre nem tartalmaz más global_using_directive. Így a társ global_using_directivevagy egy másik fordítási egységből származók nem befolyásolják egymást, és az írásuk sorrendje jelentéktelen. A global_using_directive hatóköre nem foglalja magában a program bármely összeállítási egységében azonnal található using_directive.

A global_using_directive programhoz való hozzáadásának hatása egy hasonló using_directive hozzáadásának hatása, amely ugyanahhoz a célnévtérhez feloldható, vagy a program összes fordítási egységéhez beírható. A global_using_directive célja azonban az azt tartalmazó fordítási egység kontextusában lesz feloldva. végjegyzet

14.5.2 Globális alias irányelvek használatával

A global_using_alias_directive olyan azonosítót vezet be, amely aliasként szolgál egy névtérhez vagy típushoz a programban.

global_using_alias_directive
    : 'global' using_alias_directive
    ;

A global_using_alias_directive tartalmazó programok bármely összeállítási egységében található tagdeklarációkban a global_using_alias_directive által bevezetett azonosító használható a megadott névtérre vagy típusra való hivatkozáshoz.

A global_using_alias_directiveazonosítójának egyedinek kell lennie a global_using_alias_directive tartalmazó program bármely fordítási egységének deklarációs területén belül.

A normál tagokhoz hasonlóan a global_using_alias_directiveáltal bevezetett neveket is elrejtik a beágyazott hatókörök hasonló nevű tagjai.

A global_using_alias_directiveírási sorrendjének nincs jelentősége, és a global_using_alias_directive hivatkozott namespace_or_type_name felbontását nem befolyásolja maga a global_using_alias_directive, sem a program más global_using_directivevagy using_directives. Más szóval, a global_using_alias_directive namespace_or_type_name úgy oldják fel, mintha az azonnal tartalmazó összeállítási egységnek nem volt using_directives-e, és az egész programnak nem volt global_using_directives. A global_using_alias_directive azonban hatással lehet extern_alias_directiveaz azonnal tartalmazó összeállítási egységben.

A global_using_alias_directive bármilyen névtérhez vagy típushoz létrehozhat aliast.

A névtér vagy a típus aliason keresztüli elérése pontosan ugyanazt az eredményt eredményezi, mint az adott névtér elérése vagy a deklarált név alapján történő beírás.

Az aliasok használatával zárt, konstruktált típust nevezhet el, de nem nevezhet el kötetlen általános típusdeklarációt típusargumentumok megadása nélkül.

14.5.3 Globális névtér-irányelvek használatával

Egy global_using_namespace_directive a névtérben található típusokat importálja a programba, így az egyes típusok azonosítója minősítés nélkül használható.

global_using_namespace_directive
    : 'global' using_namespace_directive
    ;

Egy global_using_namespace_directive tartalmazó program tagdeklarációiban a megadott névtérben található típusok közvetlenül hivatkozhatók.

A global_using_namespace_directive importálja a megadott névtérben található típusokat, de nem importál beágyazott névtereket.

A global_using_alias_directive ellentétben a global_using_namespace_directive importálhatnak olyan típusokat, amelyek azonosítói már definiálva vannak a program fordítási egységében. Valójában egy adott fordítási egységben a program bármely global_using_namespace_directive által importált neveket a fordítási egység hasonló nevű tagjai elrejtik.

Ha ugyanazon program global_using_namespace_directives vagy global_using_static_directiveáltal importált több névtér vagy típus azonos néven tartalmaz típusokat, akkor az adott névre type_name való hivatkozások nem egyértelműnek minősülnek.

Továbbá, ha ugyanazon program global_using_namespace_directives vagy global_using_static_directiveáltal importált több névtér vagy típus azonos néven tartalmaz típusokat vagy tagokat, az adott névre való hivatkozás simple_name nem egyértelmű.

A global_using_namespace_directive által hivatkozott namespace_name ugyanúgy oldjuk fel, mint a global_using_alias_directive hivatkozott namespace_or_type_name. Így global_using_namespace_directiveugyanabban a programban nem érintik egymást, és bármilyen sorrendben írhatók.

14.5.4 Globális statikus irányelvek használatával

A global_using_static_directive közvetlenül a típusdeklarációban található beágyazott típusokat és statikus tagokat importálja a kódoló programba, így az egyes tagok és típusok azonosítóját minősítés nélkül lehet használni.

global_using_static_directive
    : 'global' using_static_directive
    ;

A global_using_static_directive tartalmazó program tagdeklarációiban közvetlenül az adott típus deklarációjában található akadálymentes beágyazott típusok és statikus tagok (a bővítménymetelyek kivételével) közvetlenül hivatkozhatók.

A global_using_static_directive nem importálja közvetlenül statikus metódusként a bővítménymetódusokat, hanem elérhetővé teszi őket a bővítménymetódus meghívásához.

A global_using_static_directive csak az adott típusban közvetlenül deklarált tagokat és típusokat importálja, az alaposztályokban deklarált tagokat és típusokat nem.

A több global_using_namespace_directiveés global_using_static_directives közötti kétértelműségeket a 14.5.3.

14.6 Irányelvek használata

14.6.1 Általános

A használati irányelv megkönnyíti a más névterekben definiált névterek és típusok használatát. Az irányelvek használata hatással van namespace_or_type_name s (7.8. §) és simple_name(12.8.4. §) névfeloldási folyamatára, de a deklarációkkal ellentétben a using_directive-eknem járulnak hozzá új tagokhoz azon összeállítási egységek vagy névterek mögöttes deklarációs tereihez, amelyeken belül használják őket.

using_directive
    : using_alias_directive
    | using_namespace_directive
    | using_static_directive    
    ;

A using_alias_directive (14.6.2. §) egy névtérhez vagy típushoz tartozó aliast vezet be.

Egy using_namespace_directive (14.6.3. §) importálja a névtér típustagokat.

Egy using_static_directive (14.6.4. §) importálja egy típus beágyazott típusait és statikus tagjait.

A using_directive hatókörét a 7.7.1.

14.6.2 Alias irányelvek használata

A using_alias_directive olyan azonosítót vezet be, amely aliasként szolgál egy névtérhez vagy típushoz az azonnali összeállítási egység vagy névtér törzsén belül.

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

A using_alias_directive tartalmazó összeállítási egység vagy névtértörzs globális attribútumaiban és tagdeklarációiban a using_alias_directive által bevezetett azonosító használható a megadott névtérre vagy típusra való hivatkozáshoz.

Example:

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

    class B: A {}
}

A névtérben lévő tagdeklarációkon belül a névtér egy aliasa, N3 így az A osztály N1.N2.A az osztályból N3.BszármazikN1.N2.A. Ugyanezt a hatást úgy érheti el, hogy létrehoz egy aliast R a következőhöz N1.N2 , majd hivatkozik R.Ará:

namespace N3
{
    using R = N1.N2;

    class B : R.A {}
}

záró példa

A extern_alias_directive tartalmazó összeállítási egységben vagy névtértörzsben lévő irányelvek, globális attribútumok és tagdeklarációk használatával a extern_alias_directive által bevezetett azonosító használható a társított névtérre való hivatkozáshoz.

Példa: Például:

namespace N1
{
    extern alias N2;

    class B : N2::A {}
}

A névtér tagdeklarációiban N1 a fenti névtér egy olyan névtér aliasa, N2 amelynek definíciója külső a program forráskódjában. Az osztály N1.B az osztályból N2.Aszármazik. Ugyanezt a hatást úgy érheti el, hogy létrehoz egy aliast A a következőhöz N2.A , majd hivatkozik Ará:

namespace N1
{
    extern alias N2;

    using A = N2::A;

    class B : A {}
}

záró példa

Egy extern_alias_directive vagy using_alias_directive elérhetővé tesz egy aliast egy adott összeállítási egységben vagy névtértörzsben, de nem járul hozzá új tagokhoz az alapul szolgáló deklarációs térhez. Más szóval az alias-irányelv nem tranzitív, hanem csak a fordítási egységre vagy névtértörzsre van hatással, amelyben ez történik.

Példa: Az alábbi kódban

namespace N3
{
    extern alias R1;

    using R2 = N1.N2;
}

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

az alias-irányelvek hatókörei, amelyek csak abban a névtértörzsben lévő tagdeklarációkra terjednek ki R1R2 , amelyben azok szerepelnek, így R1R2 nem szerepelnek a második névtér-deklarációban. Ha azonban az alias-irányelveket a fordítási egységben helyezi el, az alias mindkét névtér-deklarációban elérhetővé válik:

extern alias R1;

using R2 = N1.N2;

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

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

záró példa

Egy compilation_unit vagy namespace_body minden extern_alias_directive vagy using_alias_directive a közvetlenül az compilation_unit vagy namespace_body tartalmazó alias deklarációs térbe (7.3. §) ad nevet. Az alias-irányelv azonosítójának egyedinek kell lennie a megfelelő alias-deklarációs területen belül. Az aliasazonosítónak nem kell egyedinek lennie a globális deklarációs térben vagy a megfelelő névtér deklarációs területén belül.

Example:

extern alias X;
extern alias Y;

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

class Y {} // Ok

A névvel ellátott X alias használata hibát okoz, mivel már van egy alias neve X ugyanabban a fordítási egységben. A névvel ellátott Y osztály nem ütközik a névvel elnevezett Y extern aliassal, mivel ezek a nevek különböző deklarációs szóközökhöz vannak hozzáadva. Az előbbi hozzáadódik a globális deklarációs térhez, az utóbbi pedig a fordítási egység alias deklarációs területéhez.

Ha egy aliasnév megegyezik egy névtér egy tagjának nevével, a névtér használatát megfelelően kell minősíteni:

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
}

A második névtértörzsben N3az eredmények nem minősített használata B hibát eredményez, mivel N3 tartalmaz egy tagot, B és a névtér törzsét, amely szintén névvel Brendelkező aliast deklarál; hasonlóképpen a következőhöz A: . Az osztály N3.B hivatkozásként vagy N3.Bnéven is hivatkozhatglobal::N3.B. Az alias Aegy minősített alias-tagban (14.9. §) használható, például A::B. Az alias B lényegében haszontalan. Nem használható qualified_alias_member , mivel csak névtér-aliasok használhatók qualified_alias_member és B aliasok egy típusban.

záró példa

A normál tagokhoz hasonlóan a alias_directives által bevezetett neveket is elrejtik a hasonló nevű tagok a beágyazott hatókörökben.

Példa: Az alábbi kódban

using R = N1.N2;

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

a deklarációban szereplő R.A hivatkozás fordítási időt eredményez, mert B nem RN3.R.N1.N2

záró példa

Az extern_alias_directiveírási sorrendjének nincs jelentősége. Hasonlóképpen, az using_alias_directiveírási sorrendjének nincs jelentősége, de minden using_alias_directives ugyanazon összeállítási egységben vagy névtértörzsben lévő összes extern_alias_directiveután kell érkeznie. A using_alias_directive által hivatkozott namespace_or_type_name felbontását nem befolyásolja az using_alias_directivevagy afordítási egységet vagy névtér törzsét közvetlenül tartalmazó using_directive, de az közvetlenül tartalmazó összeállítási egység vagy névtér törzsében lévő extern_alias_directives-ek is érinthetik. És ha a using_alias_directive azonnal tartalmazza egy fordítási egység, nem befolyásolja a global_using_directives a program. Más szóval, a using_alias_directive namespace_or_type_name úgy oldják fel, mintha az azonnal tartalmazó összeállítási egység vagy névtértörzs nem tartalmazott volna using_directives-t, és ha a using_alias_directive azonnal tartalmazza egy összeállítási egységben, a programnak nem volt global_using_directives, de a megfelelő extern_alias_directives készlettel rendelkezik.

Példa: Az alábbi kódban

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
}

az utolsó using_alias_directive fordítási időt érintő hibát eredményez, mert az előző using_alias_directive nem érinti. Az első using_alias_directive nem eredményez hibát, mivel az X extern alias hatóköre tartalmazza a using_alias_directive.

záró példa

A using_alias_directive bármilyen névtérhez vagy típushoz létrehozhat aliast, beleértve a névteret, amelyen belül megjelenik, valamint bármely névteret vagy típust, amely az adott névtérbe van ágyazva.

A névtér vagy a típus aliason keresztüli elérése pontosan ugyanazt az eredményt eredményezi, mint az adott névtér elérése vagy a deklarált név alapján történő beírás.

Példa: Adott

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

a nevek N1.N2.A, R1.N2.Aés R2.A egyenértékűek, és mind arra az osztálydeklarációra hivatkoznak , amelynek teljes neve N1.N2.A.

záró példa

Bár a részleges típus minden része (15.2.7. §) ugyanabban a névtérben van deklarálva, a részek általában különböző névtér-deklarációkban vannak megírva. Így minden résznél különböző extern_alias_directiveés using_directivelehet jelen. Az egyszerű nevek (12.8.4.§) egy részen belüli értelmezésekor csak a névtértestek és az azt tartalmazó összeállítási egység extern_alias_directiveés using_directives-jét kell figyelembe venni. Ez azt eredményezheti, hogy ugyanaz az azonosító eltérő jelentéssel rendelkezik a különböző részekben.

Example:

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

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

namespace N
{
    using List = Widgets.LinkedList;

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

záró példa

Az aliasok használatával zárt, konstruktált típust nevezhet el, de nem nevezhet el kötetlen általános típusdeklarációt típusargumentumok megadása nélkül.

Example:

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

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

záró példa

14.6.3 Névtér-irányelvek használata

Egy using_namespace_directive importálja a névtérben található típusokat az azonnal belefoglalt összeállítási egységbe vagy névtértörzsbe, így az egyes típusok azonosítója minősítés nélkül használható.

using_namespace_directive
    : 'using' namespace_name ';'
    ;

A using_namespace_directive tartalmazó összeállítási egységben vagy névtértörzsben lévő tagdeklarációkban a megadott névtérben található típusok közvetlenül hivatkozhatók.

Example:

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1.N2;

    class B : A {}
}

A névtér tagdeklarációiban a névtérben N3 lévő tag típusú tagok N1.N2 közvetlenül elérhetők, így az osztály N3.B az osztályból N1.N2.Aszármazik.

záró példa

Egy using_namespace_directive importálja a megadott névtérben található típusokat, de nem importál beágyazott névtereket.

Példa: Az alábbi kódban

namespace N1.N2
{
    class A {}
}

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

a using_namespace_directive importálja a benne található N1típusokat, de a beágyazott N1névterek nem. Így az eredmények deklarációjában N2.A szereplő hivatkozás B fordítási idejű hibába ütközik, mivel egyetlen tag sem szerepel N2 a hatókörben.

záró példa

A using_alias_directive ellentétben a using_namespace_directive olyan típusokat importálhatnak, amelyek azonosítói már definiálva vannak az összeállítási egység vagy a névtér törzsében. A using_namespace_directive által importált neveket valójában a hasonló nevű tagok rejtik el az összeállítási egység vagy névtér törzsében.

Example:

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

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

Itt a névtérben lévő tagdeklarációkon belül nem N3 a névtérre, hanem Aa névtérre N3.A hivatkozikN1.N2.A.

záró példa

Mivel a nevek nem egyértelműk, ha egynél több importált névtér ugyanazt a típusnevet használja, a using_alias_directive hasznos lehet a hivatkozás egyértelműsítése.

Példa: Az alábbi kódban

namespace N1
{
    class A {}
}

namespace N2
{
    class A {}
}

namespace N3
{
    using N1;
    using N2;

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

és N1 tartalmaz egy tagotN2, és mivel A mindkét importálást importálja, a hivatkozás N3A fordítási időt érintő N3 hiba. Ebben az esetben az ütközés a hivatkozás Aminősítésével vagy egy adott A bevezetésével oldható meg . Például:

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

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

záró példa

Továbbá, ha az using_namespace_directives vagy using_static_directiveáltal importált több névtér vagy típus ugyanabban a fordítási egységben vagy névtértörzsben azonos névvel tartalmaz típusokat vagy tagokat, akkor az adott névre simple_name való hivatkozások nem egyértelműnek minősülnek.

Example:

namespace N1
{
    class A {}
}

class C
{
    public static int A;
}

namespace N2
{
    using N1;
    using static C;

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

N1 tartalmaz egy típustagot A, és C egy statikus mezőt Atartalmaz, és mivel N2 mindkettőt importálja, A a simple_name hivatkozás nem egyértelmű, és fordítási időhiba.

záró példa

A using_alias_directive-hez hasonlóan a using_namespace_directive sem járul hozzá új tagokhoz a fordítási egység vagy névtér mögöttes deklarációs teréhez, hanem csak a fordítási egységre vagy névtértörzsre van hatással, amelyben megjelenik.

A using_namespace_directive által hivatkozott namespace_name a using_alias_directive által hivatkozott namespace_or_type_name hasonlóan oldja fel. Így using_namespace_directives ugyanabban a fordítási egységben vagy névtér törzsben nincs hatással egymásra, és bármilyen sorrendben írható.

14.6.4 Statikus irányelvek használata

A using_static_directive közvetlenül a típusdeklarációban szereplő beágyazott típusokat és statikus tagokat importálja az azonnali összeállítási egységbe vagy névtértörzsbe, lehetővé téve az egyes tagok és típusok azonosítójának minősítés nélküli használatát.

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

A using_static_directive tartalmazó összeállítási egységben vagy névtértörzsben található tagdeklarációkban közvetlenül hivatkozhat az adott típus deklarációjában közvetlenül a beágyazott típusok és statikus tagok (a bővítménymetelyek kivételével).

Example:

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

namespace N2
{
    using static N1.A;

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

Az előző kódban a névtérben lévő tagdeklarációkban N2 a statikus tagok és a beágyazott típusok N1.A közvetlenül elérhetők, így a metódus N hivatkozni tud mind a tagokra, mind a BM tagokra N1.A.

záró példa

A using_static_directive nem importálja közvetlenül statikus metódusként a bővítménymetódusokat, hanem elérhetővé teszi őket a bővítménymetódus-meghíváshoz (12.8.10.3. §).

Example:

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

namespace N2
{
    using static N1.A;

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

a using_static_directive importálja a bővítménymetódust MN1.A, de csak bővítménymetódusként. Így az első hivatkozás M az eredmények törzsében B.N fordítási idő hibába ütközik, mivel egyetlen tag sem szerepel M a hatókörben.

záró példa

A using_static_directive csak az adott típusban közvetlenül deklarált tagokat és típusokat importálja, az alaposztályokban deklarált tagokat és típusokat nem.

Example:

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

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

namespace N2
{
    using static N1.B;

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

a using_static_directive importálja a benne foglalt M2metódust N1.B , de nem importálja a benne foglalt metódustMN1.A. Így az eredmények törzsében M lévő hivatkozás C.N fordítási idő típusú hibába ütközik, mivel egyetlen tag sem szerepel M a hatókörben. A fejlesztőknek hozzá kell adni egy második using static irányelvet, amely meghatározza, hogy a metódusokat N1.A is importálni kell.

záró példa

A több using_namespace_directives és using_static_directives közötti kétértelműségeket a 14.6.3.

14.7 Névtértag-deklarációk

A namespace_member_declarationnamespace_declaration (14.3. §) vagy type_declaration (14.8. §).

namespace_member_declaration
    : namespace_declaration
    | type_declaration
    ;

A fordítási egység vagy a névtértörzs tartalmazhat namespace_member_declarations-t, és ezek a deklarációk új tagokat adnak hozzá az azt tartalmazó összeállítási egység vagy névtértörzs mögöttes deklarációs területéhez.

14.8 Típusdeklarációk

A type_declarationclass_declaration (15.2.§), struct_declaration (16.2.§), interface_declaration (19.2.§), enum_declaration (20.2. §) vagy delegate_declaration (21.2. §).

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

A type_declaration egy összeállítási egység legfelső szintű deklarációjaként vagy tagdeklarációként is előfordulhat egy névtérben, osztályban vagy szerkezetben.

Ha egy típus T típusdeklarációja legfelső szintű deklarációként történik egy fordítási egységben, a típusdeklaráció teljes neve (7.8.3. §) megegyezik a deklaráció nem minősített nevével (7.8.2. §). Ha egy típus T típusdeklarációja névtérben, osztályban vagy strukturált deklarációban történik, a típusdeklaráció teljes neve (S.N), ahol S a névtér, osztály vagy szerkezet deklaráció teljes neve, és N a deklaráció nem minősített neve.

Az osztályon, interfészen vagy szerkezeten belül deklarált típusokat beágyazott típusnak nevezzük (15.3.9. §).

A megengedett hozzáférési módosítók és a típusdeklaráció alapértelmezett hozzáférése attól függ, hogy milyen környezetben történik a deklaráció (7.5.2. §):

  • A fordítási egységekben vagy névterekben deklarált típusok rendelkezhetnek public vagy internal érhetők el. Az alapértelmezett a internal hozzáférés.
  • Az osztályokban deklarált típusok rendelkezhetnek public, protected internal, protected, private protected, internalvagy private hozzáféréssel. Az alapértelmezett a private hozzáférés.
  • A szerkezetekben deklarált típusok rendelkezhetnek publichozzáféréssel internalvagy private hozzáféréssel. Az alapértelmezett a private hozzáférés.

14.9 Minősített aliastag

14.9.1 Általános

A lehetővé teszi annak biztosítását, hogy a típusnév-kereséseket ne befolyásolja az új típusok és tagok bevezetése. A névtér alias-minősítője mindig két, bal és jobb oldali azonosítónak nevezett azonosító között jelenik meg. A normál . minősítőtől eltérően a minősítő bal oldali azonosítója :: csak externként vagy alias használatával kereshető meg.

A qualified_alias_member explicit hozzáférést biztosít a globális névtérhez, valamint a más entitások által esetleg rejtett aliasok kiirtásához vagy használatához.

qualified_alias_member
    : identifier '::' identifier type_argument_list?
    ;

A qualified_alias_memberhasználható namespace_or_type_name (7.8.§) vagy bal operandusként egy member_access (12.8.7. §).

A qualified_alias_member két azonosítóból állnak, amelyeket bal és jobb oldali azonosítónak nevezünk, amelyeket a :: jogkivonat jelöl, és opcionálisan egy type_argument_list követ. Ha a bal oldali azonosító globális, akkor a globális névtér a jobb oldali azonosítót keresi. Bármely más bal oldali azonosító esetén az azonosítót externként vagy aliasként kell keresni (14.4. § , 14.6.2. §). Fordítási időhiba akkor fordul elő, ha nincs ilyen alias, vagy az alias egy típusra hivatkozik. Ha az alias egy névtérre hivatkozik, akkor a névtér a jobb oldali azonosítót keresi.

A qualified_alias_member két űrlap egyikével rendelkezik:

  • N::I<A₁, ..., Aₑ>, ahol N és I képviseli az azonosítókat, és <A₁, ..., Aₑ> egy típusargumentumlista. (e mindig legalább egy.)
  • N::I, az azonosítók helyét N és I jelölését. (Ebben az esetben e nullának számít.)

Ezzel a jelöléssel egy qualified_alias_member jelentését a következőképpen határozzuk meg:

  • Ha N az azonosító global, akkor a globális névtér a következőre Ikeres:
    • Ha a globális névtér egy névteret I tartalmaz, és e nulla, akkor a qualified_alias_member erre a névtérre hivatkozik.
    • Ellenkező esetben, ha a globális névtér nem általános típusú nevet I tartalmaz, és e nulla, akkor a qualified_alias_member erre a típusra hivatkozik.
    • Ellenkező esetben, ha a globális névtér tartalmaz egy típusparaméterekkel rendelkező I típuste, akkor a qualified_alias_member az adott típusargumentumokkal létrehozott típusra hivatkozik.
    • Ellenkező esetben a qualified_alias_member nincs definiálva, és fordítási időhiba lép fel.
  • Ellenkező esetben a qualified_alias_member (ha van ilyen) közvetlenül tartalmazó névtér-deklarációval (14.3. §) kezdve az egyes magában foglaló névtérdeklarációval (ha van ilyen), és a qualified_alias_member tartalmazó fordítási egységgel végződik, a következő lépések lesznek kiértékelve, amíg egy entitás nem található:
    • Ha a névtér-deklaráció vagy fordítási egység tartalmaz egy using_alias_directive , amely az N-t társítja egy típushoz, vagy ha egy fordítási egység elérésekor a program egy típushoz társított N global_using_alias_directive tartalmaz, akkor a qualified_alias_member nincs definiálva, és fordítási időhiba lép fel.
    • Ellenkező esetben, ha a névtér-deklaráció vagy fordítási egység egy névtérhez társított N extern_alias_directive vagy using_alias_directive tartalmaz, vagy ha egy fordítási egység elérésekor a program egy névtérhez társított Nglobal_using_alias_directive tartalmaz, akkor:
      • Ha a N társított névtér egy I nevű névteret tartalmaz, és e nulla, akkor a qualified_alias_member erre a névtérre hivatkozik.
      • Ellenkező esetben, ha a N társított névtér egy nem általános típusú, I nevű típust tartalmaz, és e nulla, akkor a qualified_alias_member erre a típusra hivatkozik.
      • Ellenkező esetben, ha a N társított névtér tartalmaz egy I nevű típust, amely e típusparaméterekkel rendelkezik, akkor a qualified_alias_member az adott típusargumentumokkal létrehozott típusra hivatkozik.
      • Ellenkező esetben a qualified_alias_member nincs definiálva, és fordítási időhiba lép fel.
  • Ellenkező esetben a qualified_alias_member nincs definiálva, és fordítási időhiba lép fel.

Példa: A kódban:

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

az osztályra A hivatkozik global::A , a típus System.Net.Sockets.Socket pedig a következőre S::Sockethivatkozik: . A használat A.x és S.Socket ahelyett fordítási időt eredményezett volna, mert AS az a paraméterekre lett volna megoldva.

záró példa

Megjegyzés: Az azonosítónak global csak akkor van különleges jelentése, ha egy qualified_alias_name bal oldali azonosítójaként használják. Ez nem egy kulcsszó, és maga nem alias; környezetfüggő kulcsszó (6.4.4. §). A kódban:

class A { }

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

fordítási global.A idő hibát okoz, mivel a hatókörben nincs elnevezett global entitás. Ha egy globális nevű entitás hatókörben lenne, akkor global az global.A adott entitásra lett volna feloldva.

Ha egy qualified_alias_member bal oldali azonosítójaként használglobal, az mindig keres a global névtérben, még akkor is, ha van egy alias neve.global A kódban:

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 MyGlobalTypes.A a globális névtérben lévő osztályra global::A oldja fel és A oldja fel a feloldásokat.

végjegyzet

14.9.2 Az aliasok egyedisége

Minden fordítási egység és névtér törzse külön deklarációs térrel rendelkezik a felesleges aliasok és aliasok használatához. Így míg az extern alias vagy az alias használata egyedinek kell lennie az extern aliasok halmazán belül, és a fordítási egységet vagy névtér törzsét tartalmazó közvetlenül deklarált aliasokat használja, az aliasok csak a típussal vagy névtérrel azonos nevet kaphatnak, feltéve, hogy csak a :: minősítővel használják.

Példa: Az alábbiakban:

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

a névnek A két lehetséges jelentése van a második névtér törzsében, mivel az osztály A és a használó alias A is hatókörben van. Ezért a minősített név A használata A.Stream nem egyértelmű, és fordítási idő hibát okoz. A minősítő használata A:: azonban nem hiba, mert A csak névtér-aliasként jelenik meg.

záró példa