Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
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_directive, gefolgt 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, haben jedoch keine Auswirkungen auf andere Kompilierungseinheiten.
Die global_attributes (§23.3) einer Kompilierungseinheit erlauben 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 mitglieder zu einem einzigen Deklarationsraum mit dem Namen des globalen Namespaces bei.
Example:
// 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
AundB. 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 ein 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_declarations tragen Elemente zum Deklarationsraum des Namespaces bei. Beachten Sie, dass alle using_directivevor allen 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.
Example:
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.3) 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.AundN1.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_directiveund using_alias_directives finden 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
XY, 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
XundY, aber die tatsächlichen Definitionen der Aliase sind außerhalb des Programms. Auf die identisch benanntenN.BKlassen kann nun unterX.N.BVerwendung des NamespacealiasqualifizierersY.N.BundX::N.BdesY::N.BNamespaces verwiesen werden. Endbeispiel
14.5 Verwenden von Direktiven
14.5.1 Allgemein
Eine Using-Direktive 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_names (§7.8) und simple_names (§12.8.4) aus, aber im Gegensatz zu Deklarationen tragen using_directivenicht zu den zugrunde liegenden Deklarationsräumen der Kompilierungseinheiten oder Namespaces bei, in denen sie 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 den namespace_member_declarations seines unmittelbar enthaltenden Kompilierungseinheits- oder Namespacetexts. Der Umfang eines using_directive schließt insbesondere seinen Peer using_directives nicht 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.
Example:
namespace N1.N2 { class A {} } namespace N3 { using A = N1.N2.A; class B: A {} }Oben, innerhalb von Memberdeklarationen im
N3Namespace,Aist ein Alias fürN1.N2.A, und somit wird die KlasseN3.Bvon der KlasseN1.N2.Aabgeleitet. Derselbe Effekt kann durch Erstellen eines AliasRfürN1.N2und anschließendes VerweisenR.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
N1Namespace,N2ist ein Alias für einige Namespaces, deren Definition außerhalb des Quellcodes des Programms ist. Die KlasseN1.Bwird von der KlasseN2.Aabgeleitet. Derselbe Effekt kann durch Erstellen eines AliasAfürN2.Aund anschließendes VerweisenAabgerufen 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
R1undR2nur erweitern, in dem sie enthalten sind, undR1sind daherR2in 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 einen Namen 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.
Example:
extern alias X; extern alias Y; using X = N1.N2; // Error: alias X already exists class Y {} // OkDer benannte
XAlias verursacht einen Fehler, da bereits ein Alias vorhanden ist, der in derselben Kompilierungseinheit benanntXist. Die benannteYKlasse steht nicht im Konflikt mit dem externen Alias, der benanntYwird, 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 vonBErgebnissen in einem Fehler, daN3enthält ein Element benanntBund der Namespacetext, der auch einen Alias mit NamenBdeklariert ; ebenso fürA. Auf die KlasseN3.Bkann verwiesen werden alsN3.Boderglobal::N3.B. Der AliasAkann in einem qualified-alias-member (§14.8) verwendet werden, zA::B. B. . Der AliasBist im Wesentlichen nutzlos. Sie kann nicht in einer qualified_alias_member verwendet werden, da nur Namespacealias in einem qualified_alias_member undBAliasen eines Typs verwendet werden können.Endbeispiel
Genau wie normale Member werden von alias_directives eingeführte Namen 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.Ader Deklaration derBUrsache für einen Kompilierungszeitfehler, daRsich auf , nichtN3.RaufN1.N2.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 von einem using_alias_directive referenzierten namespace_or_type_name wird von der using_alias_directive selbst oder von anderen using_directives im unmittelbar enthaltenden Kompilierungseinheit oder Namespacetext nicht beeinflusst, kann aber von extern_alias_directives im 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. Die 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 einen 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.AundR2.Asind gleichwertig und alle verweisen auf die Klassendeklaration, deren vollqualifizierter Name istN1.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.
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 } }Endbeispiel
Die Verwendung von Aliasen kann einen geschlossenen konstruierten Typ benennen, aber keine ungebundene generische Typdeklaration ohne Angabe von Typargumenten benennen.
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 }Endbeispiel
14.5.3 Verwenden von Namespacedirektiven
Ein using_namespace_directive importiert die in einem Namespace enthaltenen Typen in die sofort eingeschlossene Kompilierungseinheit oder den Namespacetext, wodurch der Bezeichner der einzelnen Typen 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.
Example:
namespace N1.N2 { class A {} } namespace N3 { using N1.N2; class B : A {} }Oben sind innerhalb von Memberdeklarationen im
N3Namespace die TypmemberN1.N2direkt verfügbar und somitN3.Bvon der KlasseN1.N2.Aabgeleitet.Endbeispiel
Ein using_namespace_directive importiert die im angegebenen Namespace enthaltenen Typen, importiert 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 inN1geschachtelten Namespaces . Der Verweis inN2.Ader Deklaration vonBErgebnissen führt daher zu einem Kompilierungszeitfehler, da keine benanntenN2Elemente 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.
Example:
namespace N1.N2 { class A {} class B {} } namespace N3 { using N1.N2; class A {} }Hier bezieht sich
N3innerhalb von Memberdeklarationen imANamespaceN3.Aanstelle vonN1.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
N1ein ElementN2enthaltenA, und daN3beide importiert werden, ist das VerweisenAinN3einen Kompilierungszeitfehler. In dieser Situation kann der Konflikt entweder durch die Qualifizierung von VerweisenAauf oder durch einführung eines using_alias_directive gelöst werden, das eine bestimmteAAuswahl vornimmt. Beispiel:namespace N3 { using N1; using N2; using A = N1.A; class B : A {} // A means N1.A }Endbeispiel
Wenn mehrere Namespaces oder Typen, die von using_namespace_directives oder using_static_directives in derselben Kompilierungseinheit oder im selben Namespacetext importiert wurden, Typen oder Member mit demselben Namen enthalten, werden Verweise auf diesen Namen simple_name als mehrdeutig angesehen.
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 } } }
N1enthält ein TypelementAundCenthält ein statisches FeldA, und daN2beide importiert werden, ist das VerweisenAauf ein simple_name mehrdeutig und ein Kompilierungszeitfehler.Endbeispiel
Wie bei einem using_alias_directive trägt ein using_namespace_directive keine neuen Member zum zugrunde liegenden Deklarationsbereich der Kompilierungseinheit oder des Namespaces bei, sondern wirkt sich vielmehr nur auf die Kompilierungseinheit oder den Namespacetext aus, in der sie 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 Member, die direkt in einer Typdeklaration enthalten sind, in den unmittelbar eingeschlossenen Kompilierungseinheit oder Namespacetext, sodass 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 enthalten, können direkt auf die in der Deklaration des angegebenen Typs enthaltenen verschachtelten Typen und statische Member (mit Ausnahme von Erweiterungsmethoden) direkt verwiesen werden.
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(); } } }Im vorherigen Code sind innerhalb von Memberdeklarationen im
N2Namespace die statischen Member und geschachtelten TypenN1.Adirekt verfügbar und somit kann die MethodeNsowohl auf die AlsBauch auf dieMMember vonN1.Averweisen.Endbeispiel
Ein using_static_directive importiert Erweiterungsmethoden nicht direkt als statische Methoden, stellt sie jedoch für Den Aufruf der Erweiterungsmethode (§12.8.10.3) zur Verfügung.
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 } } }die using_static_directive importiert die in
M, aber nur als Erweiterungsmethode enthaltene ErweiterungsmethodeN1.A. Der erste Verweis imMTextkörper führtB.Ndaher zu einem Kompilierungszeitfehler, da keine benanntenMElemente 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.
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 } } }die using_static_directive importiert die
M2methodeN1.Benthalten, importiert jedoch nicht dieMinN1.A. Der Verweis imMTextkörper führtC.Ndaher zu einem Kompilierungszeitfehler, da keine benanntenMElemente im Bereich liegen. Entwickler müssen eine zweiteusing staticDirektive hinzufügen, um anzugeben, dass die MethodenN1.Aebenfalls 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
Ein 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 (§19.2), ein enum_declaration (§20.2) oder ein delegate_declaration (§21.2).
type_declaration
: class_declaration
| struct_declaration
| interface_declaration
| enum_declaration
| delegate_declaration
;
Ein 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.3) der Typdeklaration dem nicht qualifizierten Namen der Deklaration (§7.8.2). Wenn eine Typdeklaration für einen Typ T innerhalb einer Namespace-, Klassen- oder Strukturdeklaration auftritt, ist der vollqualifizierte Name (S.N) der Typdeklaration , 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, Schnittstelle 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
publicinternaldarauf zugreifen. Der Standard istinternalDer Zugriff. - In Klassen deklarierte Typen können über , ,
public, , oderprotected internalprotectedZugriff verfügenprivate protected.internalprivateDer Standard istprivateDer Zugriff. - In Struktur deklarierte Typen können über ,
publicoderinternalZugriff verfügenprivate. Der Standard istprivateDer Zugriff.
14.8 Qualifiziertes Alias-Mitglied
14.8.1 Allgemein
Der 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 extern oder mithilfe 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ₑ>, wobeiNundIstellen Sie Bezeichner dar und<A₁, ..., Aₑ>ist eine Typargumentliste. (eist immer mindestens eins.) -
N::I, wobeiNundIstellen Sie Bezeichner dar. (In diesem Fallewird als Null betrachtet.)
Bei Verwendung dieser Schreibweise wird die Bedeutung eines qualified_alias_member wie folgt bestimmt:
- Wenn
Nes sich um den Bezeichnerglobalhandelt, wird der globale Namespace durchsuchtI:- Wenn der globale Namespace einen Namespace mit dem Namen
Ie"Null" enthält, bezieht sich die qualified_alias_member auf diesen Namespace. - Andernfalls bezieht sich die
Iauf diesen Typ, wenn der globale Namespace einen nicht generischen Typ mit dem NameneNull enthält. - Andernfalls bezieht sich die
Iauf diesen Typ, der mit den angegebenen Typargumenten erstellt wurde, wenn der globale Namespace einen Typ miteTypparametern enthält. - Andernfalls ist die qualified_alias_member nicht definiert, und ein Kompilierungszeitfehler tritt auf.
- Wenn der globale Namespace einen Namespace mit dem Namen
- Andernfalls werden beginnend mit der Namespacedeklaration (§14.3) sofort die qualified_alias_member (falls vorhanden), die mit jeder eingeschlossenen Namespacedeklaration (falls vorhanden) fortgesetzt und mit der Kompilierungseinheit mit dem qualified_alias_member endet, 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.
- Wenn andernfalls die Namespacedeklaration oder Kompilierungseinheit eine extern_alias_directive oder using_alias_directive enthält, die einem Namespace zugeordnet sind
N, dann:- Wenn der mit dem Namespace verknüpfte
NNamespace einen Namespace mit dem NamenINull enthält,ebezieht sich die qualified_alias_member auf diesen Namespace. - Andernfalls bezieht sich die
Nauf diesen Typ, wenn der zugeordneteINamespace einen nicht generischen Typ mit dem NameneNull enthält. - Andernfalls bezieht sich die
Nauf diesen Typ, der mit den angegebenen Typargumenten erstellt wurde, wenn der mit einem Typ verknüpfteINamespace einen Typemit Typparametern enthält. - Andernfalls ist die qualified_alias_member nicht definiert, und ein Kompilierungszeitfehler tritt auf.
- Wenn der mit dem Namespace verknüpfte
- 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
Awird verwiesenglobal::A, und auf den TypSystem.Net.Sockets.Socketwird mitS::Socket. Die VerwendungA.xundS.Socketstattdessen haben Kompilierungszeitfehler verursacht, daAsieSin die Parameter aufgelöst wurden.Endbeispiel
Hinweis: Der Bezeichner hat nur dann eine besondere Bedeutung, wenn er als linker Bezeichner
globaleines 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.Averursacht einen Kompilierungszeitfehler, da keine Entität im Bereich benanntglobalist. Wenn eine Entität mit dem Namen "Global" den Bereich hat, wäre diesglobalglobal.Ain diese Entität aufgelöst worden.Die Verwendung
globalals linker Bezeichner eines qualified_alias_member verursacht immer einen Nachschlagevorgang imglobalNamespace, auch wenn ein verwendeter Alias mit dem Namen vorhandenglobalist. 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 inMyGlobalTypes.Adie Klasseglobal::Aim globalen Namespace aufgelöst undAaufgelöst.Hinweisende
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
Ahat zwei mögliche Bedeutungen im zweiten Namespacetext, da sowohl die KlasseAals auch der using-AliasAim Bereich liegen. Aus diesem Grund ist die Verwendung desAqualifizierten NamensA.Streammehrdeutig und verursacht einen Kompilierungszeitfehler. Die Verwendung mitAdem::Qualifizierer ist jedoch kein Fehler, daAnur als Namespacealias nachschlagen wird.Endbeispiel
ECMA C# draft specification