Freigeben über


14 Namespaces

14.1 Allgemein

C#-Programme werden mithilfe von Namespaces organisiert. Namespaces werden sowohl als "internes" Organisationssystem für ein Programm als auch als ein "externes" Organisationssystem verwendet – eine Möglichkeit, Programmelemente darzustellen, die anderen Programmen offengelegt werden.

Die Verwendung von Direktiven (§14.5) wird bereitgestellt, um die Verwendung von Namespaces zu erleichtern.

14.2 Kompilierungseinheiten

Ein compilation_unit besteht aus null oder mehr extern_alias_directivegefolgt von Null oder mehr using_directivegefolgt von Null oder einer global_attributes gefolgt von Null oder mehr namespace_member_declarations. Die compilation_unit definiert die gesamtstruktur der Eingabe.

compilation_unit
    : extern_alias_directive* using_directive* global_attributes?
      namespace_member_declaration*
    ;

Ein C#-Programm besteht aus einer oder mehreren Kompilierungseinheiten. Wenn ein C#-Programm kompiliert wird, werden alle Kompilierungseinheiten zusammen verarbeitet. So können Kompilierungseinheiten voneinander abhängig sein, möglicherweise in kreisförmiger Weise.

Die extern_alias_directiveeiner Kompilierungseinheit wirken sich auf die using_directives, global_attributes und namespace_member_declarationdieser Kompilierungseinheit aus, wirken sich jedoch nicht auf andere Kompilierungseinheiten aus.

Die using_directiveeiner Kompilierungseinheit wirken sich auf die global_attributes und namespace_member_declarationdieser Kompilierungseinheit aus, wirken sich jedoch nicht auf andere Kompilierungseinheiten aus.

Die global_attributes (§22.3) einer Kompilierungseinheit ermöglichen die Spezifikation von Attributen für die Zielassembly und das Zielmodul. Assemblys und Module dienen als physische Container für Typen. Eine Assembly kann aus mehreren physisch getrennten Modulen bestehen.

Die namespace_member_declarationjeder Kompilierungseinheit eines Programms tragen zu einem einzigen Deklarationsraum, der als globaler Namespace bezeichnet wird, bei.

Beispiel:

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

Die beiden Kompilierungseinheiten tragen zum einzelnen globalen Namespace bei, in diesem Fall zwei Klassen mit den vollqualifizierten Namen A und B. Da die beiden Kompilierungseinheiten zum gleichen Deklarationsraum beitragen, wäre es ein Fehler gewesen, wenn jede eine Deklaration eines Elements mit demselben Namen enthielt.

Endbeispiel

14.3 Namespacedeklarationen

Ein namespace_declaration besteht aus dem Schlüsselwortnamespace, gefolgt von einem Namespacenamen und -text, optional gefolgt von einem Semikolon.

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

qualified_identifier
    : identifier ('.' identifier)*
    ;

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

Eine namespace_declaration kann als Deklaration der obersten Ebene in einer compilation_unit oder als Memberdeklaration innerhalb einer anderen namespace_declaration auftreten. Wenn ein namespace_declaration als Deklaration der obersten Ebene in einem compilation_unit auftritt, wird der Namespace mitglied des globalen Namespace. Wenn ein namespace_declaration innerhalb einer anderen namespace_declaration auftritt, wird der innere Namespace zu einem Mitglied des äußeren Namespaces. In beiden Fällen muss der Name eines Namespace innerhalb des enthaltenden Namespace eindeutig sein.

Namespaces sind implizit public und die Deklaration eines Namespaces darf keine Zugriffsmodifizierer enthalten.

Innerhalb eines namespace_body importieren die optionalen using_directivedie Namen anderer Namespaces, Typen und Member, sodass sie direkt anstelle von qualifizierten Namen referenziert werden können. Die optionalen namespace_member_declarationtragen Elemente zum Deklarationsraum des Namespaces bei. Beachten Sie, dass alle using_directivevor den Mitgliedserklärungen erscheinen.

Die qualified_identifier eines namespace_declaration kann ein einzelner Bezeichner oder eine Sequenz von Bezeichnern sein, die durch "." Token getrennt sind. In letzterer Form kann ein Programm einen geschachtelten Namespace definieren, ohne mehrere Namespacedeklarationen lexikalisch zu verschachteln.

Beispiel:

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

ist semantisch gleichbedeutend mit

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

Endbeispiel

Namespaces sind offen beendet, und zwei Namespacedeklarationen mit demselben vollqualifizierten Namen (§7.8.2) tragen zum gleichen Deklarationsraum (§7.3) bei.

Beispiel: Im folgenden Code

namespace N1.N2
{
    class A {}
}

namespace N1.N2
{
    class B {}
}

Die beiden oben genannten Namespacedeklarationen tragen zum gleichen Deklarationsraum bei, in diesem Fall zwei Klassen mit den vollqualifizierten Namen N1.N2.A und N1.N2.B. Da die beiden Deklarationen zum gleichen Deklarationsraum beitragen, wäre es ein Fehler gewesen, wenn jede eine Deklaration eines Elements mit demselben Namen enthielt.

Endbeispiel

14.4 Externe Aliasdirektiven

Ein extern_alias_directive führt einen Bezeichner ein, der als Alias für einen Namespace dient. Die Spezifikation des aliasierten Namespaces ist außerhalb des Quellcodes des Programms und gilt auch für geschachtelte Namespaces des aliasierten Namespaces.

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

Der Umfang eines extern_alias_directive erstreckt sich über die using_directive, global_attributes und namespace_member_declarationseiner unmittelbar enthaltenden compilation_unit oder namespace_body.

Innerhalb einer Kompilierungseinheit oder eines Namespacetexts, der eine extern_alias_directive enthält, kann der vom extern_alias_directive eingeführte Bezeichner verwendet werden, um auf den aliasierten Namespace zu verweisen. Es handelt sich um einen Kompilierzeitfehler für den Bezeichner, der das Wort globalsein soll.

Der von einem extern_alias_directive eingeführte Alias ähnelt dem alias, der von einem using_alias_directive eingeführt wurde. Ausführlichere Erläuterungen zu extern_alias_directive und using_alias_directivefinden Sie unter §14.5.2.

alias ist ein kontextbezogenes Schlüsselwort (§6.4.4) und hat nur eine besondere Bedeutung, wenn es unmittelbar auf das extern Schlüsselwort in einem extern_alias_directive folgt.

Wenn ein Programm einen externen Alias deklariert, für den keine externe Definition bereitgestellt wird, tritt ein Fehler auf.

Beispiel: Das folgende Programm deklariert und verwendet zwei externe Aliase und X Y, die jeweils den Stamm einer unterschiedlichen Namespacehierarchie darstellen:

extern alias X;
extern alias Y;

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

Das Programm deklariert das Vorhandensein der externen Aliase X und Y, aber die tatsächlichen Definitionen der Aliase sind außerhalb des Programms. Auf die identisch benannten N.B Klassen kann nun unter X.N.B Verwendung des Namespacealiasqualifizierers X::N.B und Y.N.Bdes Y::N.BNamespaces verwiesen werden. Endbeispiel

14.5 Verwenden von Direktiven

14.5.1 Allgemein

Die Verwendung von Direktiven erleichtert die Verwendung von Namespaces und Typen, die in anderen Namespaces definiert sind. Die Verwendung von Direktiven wirkt sich auf den Namensauflösungsprozess von namespace_or_type_name s (§7.8) und simple_names (§12.8.4) aus, aber im Gegensatz zu Deklarationen tragen using_directives nicht zu den zugrunde liegenden Deklarationsräumen der Kompilierungseinheiten oder Namespaces bei, in denensie verwendet werden.

using_directive
    : using_alias_directive
    | using_namespace_directive
    | using_static_directive    
    ;

Ein using_alias_directive (§14.5.2) führt einen Alias für einen Namespace oder Typ ein.

Ein using_namespace_directive (§14.5.3) importiert die Typmember eines Namespaces.

Ein using_static_directive (§14.5.4) importiert die geschachtelten Typen und statischen Member eines Typs.

Der Umfang eines using_directive erstreckt sich über die namespace_member_declarations seines unmittelbar enthaltenden Kompilierungseinheits- oder Namespacetexts. Der Umfang eines using_directive schließt insbesondere nicht den Peer using_directives ein. Daher wirken sich Peer using_directivenicht gegenseitig aus, und die Reihenfolge, in der sie geschrieben werden, ist unbedeutend. Im Gegensatz dazu enthält der Bereich eines extern_alias_directive die in derselben Kompilierungseinheit oder im Namespacetext definierten using_directive.

14.5.2 Verwenden von Aliasdirektiven

Ein using_alias_directive führt einen Bezeichner ein, der als Alias für einen Namespace oder Typ innerhalb der unmittelbar eingeschlossenen Kompilierungseinheit oder des Namespacetexts dient.

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

Innerhalb globaler Attribute und Memberdeklarationen in einer Kompilierungseinheit oder einem Namespacetext, die ein using_alias_directive enthält, kann der vom using_alias_directive eingeführte Bezeichner verwendet werden, um auf den angegebenen Namespace oder Typ zu verweisen.

Beispiel:

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

    class B: A {}
}

Oben, innerhalb von Memberdeklarationen im N3 Namespace, A ist ein Alias für N1.N2.A, und somit wird die Klasse N3.B von der Klasse N1.N2.Aabgeleitet. Derselbe Effekt kann durch Erstellen eines Alias R für N1.N2 und anschließendes Verweisen R.Aabgerufen werden:

namespace N3
{
    using R = N1.N2;

    class B : R.A {}
}

Endbeispiel

Innerhalb der Verwendung von Direktiven, globalen Attributen und Memberdeklarationen in einer Kompilierungseinheit oder einem Namespacetext, die ein extern_alias_directive enthält, kann der vom extern_alias_directive eingeführte Bezeichner verwendet werden, um auf den zugeordneten Namespace zu verweisen.

Beispiel:

namespace N1
{
    extern alias N2;

    class B : N2::A {}
}

Oben, innerhalb von Memberdeklarationen im N1 Namespace, N2 ist ein Alias für einige Namespaces, deren Definition außerhalb des Quellcodes des Programms ist. Die Klasse N1.B wird von der Klasse N2.Aabgeleitet. Derselbe Effekt kann durch Erstellen eines Alias A für N2.A und anschließendes Verweisen Aabgerufen werden:

namespace N1
{
    extern alias N2;

    using A = N2::A;

    class B : A {}
}

Endbeispiel

Ein extern_alias_directive oder using_alias_directive stellt einen Alias in einer bestimmten Kompilierungseinheit oder einem Namespacetext zur Verfügung, trägt jedoch keine neuen Member zum zugrunde liegenden Deklarationsbereich bei. Anders ausgedrückt: Eine Aliasdirektive ist nicht transitiv, sondern wirkt sich vielmehr nur auf die Kompilierungseinheit oder den Namespacetext aus, in dem sie auftritt.

Beispiel: Im folgenden Code

namespace N3
{
    extern alias R1;

    using R2 = N1.N2;
}

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

die Bereiche der Aliasdirektiven, die Memberdeklarationen im Namespacetext einführen R1 und R2 nur erweitern, in dem sie enthalten sind, und R2 sind daher R1 in der zweiten Namespacedeklaration unbekannt. Wenn Sie jedoch die Aliasdirektiven in die enthaltende Kompilierungseinheit setzen, wird der Alias in beiden Namespacedeklarationen verfügbar:

extern alias R1;

using R2 = N1.N2;

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

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

Endbeispiel

Jede extern_alias_directive oder using_alias_directive in einem compilation_unit oder namespace_body trägt zum Aliasdeklarationsraum (§7.3) des unmittelbar eingeschlossenen compilation_unit oder namespace_body bei. Der Bezeichner der Aliasdirektive muss innerhalb des entsprechenden Aliasdeklarationsbereichs eindeutig sein. Der Aliasbezeichner muss nicht innerhalb des globalen Deklarationsbereichs oder des Deklarationsraums des entsprechenden Namespace eindeutig sein.

Beispiel:

extern alias X;
extern alias Y;

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

class Y {} // Ok

Der benannte X Alias verursacht einen Fehler, da bereits ein Alias vorhanden ist, der in derselben Kompilierungseinheit benannt X ist. Die benannte Y Klasse steht nicht im Konflikt mit dem externen Alias, der benannt Y wird, da diese Namen zu unterschiedlichen Deklarationsräumen hinzugefügt werden. Der erste wird dem globalen Deklarationsraum hinzugefügt, und letzteres wird dem Aliasdeklarationsraum für diese Kompilierungseinheit hinzugefügt.

Wenn ein Aliasname mit dem Namen eines Mitglieds eines Namespace übereinstimmt, muss die Verwendung einer der Beiden entsprechend qualifiziert sein:

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
}

Im zweiten Namespacetext für N3, nicht qualifizierte Verwendung von B Ergebnissen in einem Fehler, da N3 enthält ein Element benannt B und der Namespacetext, der auch einen Alias mit Namen Bdeklariert ; ebenso für A. Auf die Klasse N3.B kann verwiesen werden als N3.B oder global::N3.B. Der Alias A kann in einem qualified-alias-member (§14.8) verwendet werden, z A::B. B. . Der Alias B ist im Wesentlichen nutzlos. Sie kann nicht in einer qualified_alias_member verwendet werden, da nur Namespacealias in einem qualified_alias_member und B Aliasen eines Typs verwendet werden können.

Endbeispiel

Genau wie normale Member werden namen, die von alias_directives eingeführt werden, von ähnlich benannten Mitgliedern in geschachtelten Bereichen ausgeblendet.

Beispiel: Im folgenden Code

using R = N1.N2;

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

der Verweis in R.A der Deklaration der B Ursache für einen Kompilierungszeitfehler, da R sich auf , nicht N1.N2auf N3.R.

Endbeispiel

Die Reihenfolge, in der extern_alias_directivegeschrieben werden, hat keine Bedeutung. Ebenso hat die Reihenfolge, in der using_alias_directivegeschrieben werden, keine Bedeutung, aber alle using_alias_directives müssen nach allen extern_alias_directives in derselben Kompilierungseinheit oder im selben Namespacetext kommen. Die Auflösung der namespace_or_type_name, auf die von einem using_alias_directive verwiesen wird, ist nicht von der using_alias_directive selbst oder von anderen using_directiveim unmittelbar enthaltenden Kompilierungseinheit oder Namespacetext betroffen, kann aber von extern_alias_directiveim unmittelbar enthaltenden Kompilierungseinheit oder Namespacetext betroffen sein. Anders ausgedrückt: Die namespace_or_type_name eines using_alias_directive wird aufgelöst, als ob die sofort enthaltende Kompilierungseinheit oder der Namespacetext keine using_directivehatte, sondern über den richtigen Satz von extern_alias_directives verfügt.

Beispiel: Im folgenden Code

namespace N1.N2 {}

namespace N3
{
    extern alias X;

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

die letzte using_alias_directive führt zu einem Kompilierungszeitfehler, da sie von der vorherigen using_alias_directive nicht betroffen ist. Der erste using_alias_directive führt nicht zu einem Fehler, da der Bereich des externen Alias X die using_alias_directive enthält.

Endbeispiel

Ein using_alias_directive kann einen Alias für einen beliebigen Namespace oder Typ erstellen, einschließlich des Namespaces, in dem er angezeigt wird, sowie jeden Namespace oder Typ, der in diesem Namespace geschachtelt ist.

Der Zugriff auf einen Namespace oder Typ über einen Alias führt genau zum gleichen Ergebnis wie der Zugriff auf diesen Namespace oder Typ über seinen deklarierten Namen.

Beispiel: Gegeben

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

die Namen N1.N2.A, R1.N2.Aund R2.A sind gleichwertig und alle verweisen auf die Klassendeklaration, deren vollqualifizierter Name ist N1.N2.A.

Endbeispiel

Obwohl jeder Teil eines Teiltyps (§15.2.7) innerhalb desselben Namespace deklariert wird, werden die Teile in der Regel in verschiedenen Namespacedeklarationen geschrieben. Somit können für jeden Teil unterschiedliche extern_alias_directiveund using_directives vorhanden sein. Bei der Interpretation einfacher Namen (§12.8.4) innerhalb eines Teils werden nur die extern_alias_directives und using_directiveder Namespacetexte und kompilierungseinheit berücksichtigt, die diesen Teil einschließt. Dies kann dazu führen, dass derselbe Bezeichner unterschiedliche Bedeutungen in verschiedenen Teilen hat.

Beispiel:

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

Endbeispiel

Die Verwendung von Aliasen kann einen geschlossenen konstruierten Typ benennen, aber keine ungebundene generische Typdeklaration ohne Angabe von Typargumenten benennen.

Beispiel:

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
}

Endbeispiel

14.5.3 Verwenden von Namespacedirektiven

Ein using_namespace_directive importiert die in einem Namespace enthaltenen Typen in den unmittelbar eingeschlossenen Kompilierungseinheits- oder Namespacetext, wodurch der Bezeichner jedes Typs ohne Qualifikation verwendet werden kann.

using_namespace_directive
    : 'using' namespace_name ';'
    ;

Innerhalb von Memberdeklarationen in einer Kompilierungseinheit oder einem Namespacetext, die ein using_namespace_directive enthält, können die im angegebenen Namespace enthaltenen Typen direkt referenziert werden.

Beispiel:

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1.N2;

    class B : A {}
}

Oben sind innerhalb von Memberdeklarationen im N3 Namespace die Typmember N1.N2 direkt verfügbar und somit N3.B von der Klasse N1.N2.Aabgeleitet.

Endbeispiel

Ein using_namespace_directive importiert die typen, die im angegebenen Namespace enthalten sind, jedoch keine geschachtelten Namespaces.

Beispiel: Im folgenden Code

namespace N1.N2
{
    class A {}
}

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

die using_namespace_directive importiert die in N1, aber nicht die in N1geschachtelten Namespaces . Der Verweis in N2.A der Deklaration von B Ergebnissen führt daher zu einem Kompilierungszeitfehler, da keine benannten N2 Elemente im Bereich liegen.

Endbeispiel

Im Gegensatz zu einem using_alias_directive kann ein using_namespace_directive Typen importieren, deren Bezeichner bereits in der eingeschlossenen Kompilierungseinheit oder im Namespacetext definiert sind. Tatsächlich werden von einem using_namespace_directive importierte Namen von ähnlich benannten Elementen in der eingeschlossenen Kompilierungseinheit oder im Namespacetext ausgeblendet.

Beispiel:

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

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

Hier bezieht sich N3.A innerhalb von Memberdeklarationen im N3 Namespace A anstelle von N1.N2.A.

Endbeispiel

Da Namen möglicherweise mehrdeutig sind, wenn mehr als ein importierter Namespace denselben Typnamen einführt, ist eine using_alias_directive nützlich, um den Verweis zu disambiguieren.

Beispiel: Im folgenden Code

namespace N1
{
    class A {}
}

namespace N2
{
    class A {}
}

namespace N3
{
    using N1;
    using N2;

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

sowohl als auch N1 ein Element AenthaltenN2, und da N3 beide importiert werden, ist das Verweisen A in N3 einen Kompilierungszeitfehler. In dieser Situation kann der Konflikt entweder durch die Qualifizierung von Verweisen Aauf oder durch Einführung einer using_alias_directive gelöst werden, die eine bestimmte AAuswahl vornimmt. Zum Beispiel:

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

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

Endbeispiel

Wenn darüber hinaus mehrere Namespaces oder Typen, die von using_namespace_directives oder using_static_directives in derselben Kompilierungseinheit oder im selben Namespacetext importiert werden, Typen oder Member mit demselben Namen enthalten, werden Verweise auf diesen Namen als simple_name als mehrdeutig angesehen.

Beispiel:

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 enthält ein Typelement Aund C enthält ein statisches Feld A, und da N2 beide importiert werden, ist das Verweisen A auf eine simple_name mehrdeutig und ein Kompilierungszeitfehler.

Endbeispiel

Wie ein using_alias_directive trägt ein using_namespace_directive keine neuen Member zum zugrunde liegenden Deklarationsraum der Kompilierungseinheit oder des Namespaces bei, sondern betrifft vielmehr nur die Kompilierungseinheit oder den Namespacetext, in der er angezeigt wird.

Die namespace_name, auf die von einem using_namespace_directive verwiesen wird, wird auf die gleiche Weise aufgelöst wie die namespace_or_type_name, auf die von einem using_alias_directive verwiesen wird. Daher wirken sich using_namespace_directives in derselben Kompilierungseinheit oder im Namespacetext nicht gegenseitig aus und können in beliebiger Reihenfolge geschrieben werden.

14.5.4 Verwenden statischer Direktiven

Ein using_static_directive importiert die geschachtelten Typen und statischen Elemente, die direkt in einer Typdeklaration enthalten sind, in den unmittelbar eingeschlossenen Kompilierungseinheit oder Namespacetext, wodurch der Bezeichner jedes Elements und Typs ohne Qualifikation verwendet werden kann.

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

Innerhalb von Memberdeklarationen in einer Kompilierungseinheit oder einem Namespacetext, die eine using_static_directive enthält, können direkt auf die in der Deklaration des angegebenen Typs enthaltenen verschachtelten Typen und statische Member (mit Ausnahme von Erweiterungsmethoden) direkt verwiesen werden.

Beispiel:

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

Im vorherigen Code sind innerhalb von Memberdeklarationen im N2 Namespace die statischen Member und geschachtelten Typen N1.A direkt verfügbar und somit kann die Methode N sowohl auf die Als M auch auf die B Member von N1.Averweisen.

Endbeispiel

Eine using_static_directive importiert Erweiterungsmethoden nicht direkt als statische Methoden, stellt sie aber für Den Aufruf der Erweiterungsmethode (§12.8.9.3) zur Verfügung.

Beispiel:

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

die using_static_directive importiert die in N1.A, aber nur als Erweiterungsmethode enthaltene ErweiterungsmethodeM. Der erste Verweis im M Textkörper führt B.N daher zu einem Kompilierungszeitfehler, da keine benannten M Elemente im Bereich liegen.

Endbeispiel

Ein using_static_directive importiert nur Elemente und Typen, die direkt im angegebenen Typ deklariert sind, nicht Elemente und Typen, die in Basisklassen deklariert sind.

Beispiel:

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

die using_static_directive importiert die M2 methode N1.Benthalten, importiert jedoch nicht die M in N1.A. Der Verweis im M Textkörper führt C.N daher zu einem Kompilierungszeitfehler, da keine benannten M Elemente im Bereich liegen. Entwickler müssen eine zweite using static Direktive hinzufügen, um anzugeben, dass die Methoden N1.A ebenfalls importiert werden sollen.

Endbeispiel

Mehrdeutigkeiten zwischen mehreren using_namespace_directives und using_static_directives werden in §14.5.3 erläutert.

14.6 Namespace-Memberdeklarationen

Eine namespace_member_declaration ist entweder ein namespace_declaration (§14.3) oder ein type_declaration (§14.7).

namespace_member_declaration
    : namespace_declaration
    | type_declaration
    ;

Eine Kompilierungseinheit oder ein Namespacetext kann namespace_member_declarations enthalten, und solche Deklarationen tragen zum zugrunde liegenden Deklarationsraum der enthaltenden Kompilierungseinheit oder des Namespacetexts bei.

14.7 Typdeklarationen

Ein type_declaration ist ein class_declaration (§15.2), ein struct_declaration (§16.2), ein interface_declaration (§18.2), ein enum_declaration (§19.2) oder ein delegate_declaration (§20.2).

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

Eine type_declaration kann als Deklaration der obersten Ebene in einer Kompilierungseinheit oder als Memberdeklaration innerhalb eines Namespaces, einer Klasse oder einer Struktur auftreten.

Wenn eine Typdeklaration für einen Typ T als Deklaration der obersten Ebene in einer Kompilierungseinheit auftritt, entspricht der vollqualifizierte Name (§7.8.2) der Typdeklaration dem nicht qualifizierten Namen der Deklaration (§7.8.2). Wenn eine Typdeklaration für einen Typ T in einem Namespace, einer Klasse oder einer Strukturdeklaration auftritt, ist der vollqualifizierte Name (§7.8.3) der Typdeklarationen S.N, wobei S der vollqualifizierte Name der enthaltenden Namespace-, Klassen- oder Strukturdeklaration ist und N der nicht qualifizierte Name der Deklaration ist.

Ein in einer Klasse oder Struktur deklarierter Typ wird als geschachtelter Typ (§15.3.9) bezeichnet.

Die Zulässigen Zugriffsmodifizierer und der Standardzugriff für eine Typdeklaration hängen vom Kontext ab, in dem die Deklaration stattfindet (§7.5.2):

  • Typen, die in Kompilierungseinheiten oder Namespaces deklariert sind, können oder public internal darauf zugreifen. Der Standard ist internal Der Zugriff.
  • In Klassen deklarierte Typen können über , , protected internal, , oder private internalZugriff verfügenpublic. private protectedprotected Der Standard ist private Der Zugriff.
  • In Struktur deklarierte Typen können über , internaloder private Zugriff verfügenpublic. Der Standard ist private Der Zugriff.

14.8 Qualifiziertes Alias-Mitglied

14.8.1 Allgemein

Der Namespacealiasqualifizierer :: ermöglicht es, sicherzustellen, dass Typnamensuchvorgänge durch die Einführung neuer Typen und Member nicht betroffen sind. Der Namespacealiasqualifizierer wird immer zwischen zwei Bezeichnern angezeigt, die als Links- und Rechts-IDs bezeichnet werden. Im Gegensatz zum regulären . Qualifizierer wird der linke Bezeichner des :: Qualifizierers nur als extern oder mit Alias nachschlagen.

Ein qualified_alias_member bietet expliziten Zugriff auf den globalen Namespace und externe oder verwendung von Aliasen, die potenziell von anderen Entitäten ausgeblendet werden.

qualified_alias_member
    : identifier '::' identifier type_argument_list?
    ;

Ein qualified_alias_member kann als namespace_or_type_name (§7.8) oder als linker Operand in einem member_access (§12.8.7) verwendet werden.

Ein qualified_alias_member besteht aus zwei Bezeichnern, die als Links- und Rechtshand-IDs bezeichnet werden, getrennt vom :: Token und optional gefolgt von einem type_argument_list. Wenn der linkshändige Bezeichner global ist, wird der globale Namespace nach dem rechten Bezeichner gesucht. Bei anderen linkshändigen Bezeichnern wird dieser Bezeichner als extern oder unter Verwendung von Aliasen (§14.4 und §14.5.2) nachschlagen. Wenn kein solcher Alias vorhanden ist oder der Alias auf einen Typ verweist, tritt ein Kompilierungszeitfehler auf. Wenn der Alias auf einen Namespace verweist, wird dieser Namespace nach dem rechten Bezeichner gesucht.

Eine qualified_alias_member hat eine von zwei Formen:

  • N::I<A₁, ..., Aₑ>, wobei N und I stellen Sie Bezeichner dar und <A₁, ..., Aₑ> ist eine Typargumentliste. (e ist immer mindestens eins.)
  • N::I, wobei N und I stellen Sie Bezeichner dar. (In diesem Fall e wird als Null betrachtet.)

Bei Verwendung dieser Schreibweise wird die Bedeutung einer qualified_alias_member wie folgt bestimmt:

  • Wenn N es sich um den Bezeichner globalhandelt, wird der globale Namespace durchsucht I:
    • Wenn der globale Namespace einen Namespace mit dem Namen I Null enthält, e bezieht sich die qualified_alias_member auf diesen Namespace.
    • Andernfalls bezieht sich der qualified_alias_member auf diesen Typ, wenn der globale Namespace einen nicht generischen Typ mit dem Namen I e Null enthält.
    • Andernfalls bezieht sich die qualified_alias_member auf diesen Typ, der mit den angegebenen Typargumenten erstellt wurde, wenn der globale Namespace einen Typ I e mit Typparametern enthält.
    • Andernfalls ist die qualified_alias_member nicht definiert, und ein Kompilierungszeitfehler tritt auf.
  • Andernfalls werden ab der Namespacedeklaration (§14.3) sofort die qualified_alias_member (falls vorhanden) mit jeder eingeschlossenen Namespacedeklaration (falls vorhanden) fortgesetzt und mit der Kompilierungseinheit mit dem qualified_alias_member enden, die folgenden Schritte ausgewertet, bis sich eine Entität befindet:
    • Wenn die Namespacedeklaration oder Kompilierungseinheit eine using_alias_directive enthält, die N einem Typ zuordnet, ist die qualified_alias_member nicht definiert, und ein Kompilierungszeitfehler tritt auf.
    • Andernfalls, wenn die Namespacedeklaration oder Kompilierungseinheit eine extern_alias_directive oder using_alias_directive enthält, die einem Namespace zugeordnet ist N , dann:
      • Wenn der mit dem Namespace verknüpfte N Namespace einen Namespace mit dem Namen I Null enthält, e bezieht sich die qualified_alias_member auf diesen Namespace.
      • Andernfalls bezieht sich die qualified_alias_member auf diesen Typ, wenn der zugeordnete N Namespace einen nicht generischen Typ mit dem Namen I e Null enthält.
      • Andernfalls bezieht sich die qualified_alias_member auf diesen Typ, der mit den angegebenen Typargumenten erstellt wurde, wenn der mit einem Typ verknüpfte N Namespace einen Typ I mit Typparametern enthälte.
      • Andernfalls ist die qualified_alias_member nicht definiert, und ein Kompilierungszeitfehler tritt auf.
  • Andernfalls ist die qualified_alias_member nicht definiert, und ein Kompilierungszeitfehler tritt auf.

Beispiel: Im Code:

using S = System.Net.Sockets;

class A
{
    public static int x;
}

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

auf die Klasse A wird verwiesen global::A , und auf den Typ System.Net.Sockets.Socket wird mit S::Socket. Die Verwendung A.x und S.Socket stattdessen haben Kompilierungszeitfehler verursacht, da A sie S in die Parameter aufgelöst wurden.

Endbeispiel

Hinweis: Der Bezeichner hat nur eine besondere Bedeutung, wenn er als linker Bezeichner global eines qualified_alias_name verwendet wird. Es handelt sich nicht um ein Schlüsselwort und es handelt sich nicht selbst um einen Alias; es handelt sich um ein kontextbezogenes Schlüsselwort (§6.4.4). Im Code:

class A { }

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

using global.A verursacht einen Kompilierungszeitfehler, da keine Entität im Bereich benannt global ist. Wenn eine Entität mit dem Namen "Global" den Bereich hat, wäre dies global global.A in diese Entität aufgelöst worden.

Die Verwendung global als linker Bezeichner eines qualified_alias_member führt immer zu einer Suche im global Namespace, auch wenn ein verwendeter Alias mit dem Namen vorhanden globalist. Im Code:

using global = MyGlobalTypes;

class A { }

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

global.Awird in MyGlobalTypes.A die Klasse A im globalen Namespace aufgelöst und global::A aufgelöst.

Endnote

14.8.2 Eindeutigkeit von Aliasen

Jede Kompilierungseinheit und jeder Namespacetext verfügt über einen separaten Deklarationsraum für externe Aliase und die Verwendung von Aliasen. Während der Name eines externen Alias oder eines Alias innerhalb der Gruppe externer Aliase eindeutig sein muss und Aliase verwendet werden, die in der unmittelbar enthaltenen Kompilierungseinheit oder im Namespacetext deklariert sind, darf ein Alias denselben Namen wie ein Typ oder Namespace aufweisen, solange er nur mit dem :: Qualifizierer verwendet wird.

Beispiel: Im Folgenden:

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

der Name A hat zwei mögliche Bedeutungen im zweiten Namespacetext, da sowohl die Klasse A als auch der using-Alias A im Bereich liegen. Aus diesem Grund ist die Verwendung des A qualifizierten Namens A.Stream mehrdeutig und verursacht einen Kompilierungszeitfehler. Die Verwendung mit A dem :: Qualifizierer ist jedoch kein Fehler, da A nur als Namespacealias nachschlagen wird.

Endbeispiel