KlassenClasses

Eine Klasse ist eine Datenstruktur, die Daten Mitglieder (Konstanten und Feldern), Funktionsmember (Methoden, Eigenschaften, Ereignisse, Indexer, Operatoren, Instanzkonstruktoren, Destruktoren und statische Konstruktoren) und geschachtelte Typen enthalten kann.A class is a data structure that may contain data members (constants and fields), function members (methods, properties, events, indexers, operators, instance constructors, destructors and static constructors), and nested types. Klassentypen unterstützen die Vererbung, einen Mechanismus, bei dem eine abgeleitete Klasse erweitern und spezialisiert eine Basisklasse kann.Class types support inheritance, a mechanism whereby a derived class can extend and specialize a base class.

KlassendeklarationenClass declarations

Ein Class_declaration ist eine Type_declaration (Typdeklarationen), die eine neue Klasse deklariert.A class_declaration is a type_declaration (Type declarations) that declares a new class.

class_declaration
    : attributes? class_modifier* 'partial'? 'class' identifier type_parameter_list?
      class_base? type_parameter_constraints_clause* class_body ';'?
    ;

Ein Class_declaration besteht aus einer optionalen Gruppe von Attribute (Attribute), gefolgt von einer optionalen Gruppe von Class_modifiers (Klasse Modifizierer), gefolgt von einem optionalen partial Modifizierer, gefolgt vom Schlüsselwort class und ein Bezeichner mit dem Namen der Klasse, gefolgt von einem optionale Type_parameter_list (Typparameter), gefolgt von einem optionalen Class_base Spezifikation (Klasse Basis Spezifikation), gefolgt von einer optionalen Gruppe von Type_parameter_constraints_clauses (Geben Sie die Einschränkungen für Typparameter), gefolgt von einem Class_body (Klasse Text), optional gefolgt durch ein Semikolon.A class_declaration consists of an optional set of attributes (Attributes), followed by an optional set of class_modifiers (Class modifiers), followed by an optional partial modifier, followed by the keyword class and an identifier that names the class, followed by an optional type_parameter_list (Type parameters), followed by an optional class_base specification (Class base specification) , followed by an optional set of type_parameter_constraints_clauses (Type parameter constraints), followed by a class_body (Class body), optionally followed by a semicolon.

Eine Klassendeklaration kann nicht bereitstellen Type_parameter_constraints_clauses es sei denn, sie verfügt auch über eine Type_parameter_list.A class declaration cannot supply type_parameter_constraints_clauses unless it also supplies a type_parameter_list.

Eine Klassendeklaration, die bereitstellt eine Type_parameter_list ist eine generischen Klassendeklaration.A class declaration that supplies a type_parameter_list is a generic class declaration. Darüber hinaus ist jeder Klasse, die in der Deklaration einer generischen Klasse oder einer generischen Strukturdeklaration geschachtelt selbst die Deklaration einer generischen Klasse, da der Typparameter für den enthaltenden Typ angegeben werden müssen, um einen konstruierten Typ zu erstellen.Additionally, any class nested inside a generic class declaration or a generic struct declaration is itself a generic class declaration, since type parameters for the containing type must be supplied to create a constructed type.

KlassenmodifiziererClass modifiers

Ein Class_declaration kann optional eine Sequenz von Klassenmodifizierer enthalten:A class_declaration may optionally include a sequence of class modifiers:

class_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'abstract'
    | 'sealed'
    | 'static'
    | class_modifier_unsafe
    ;

Es ist ein Fehler während der Kompilierung für den gleichen Modifizierer für mehrere Male in einer Klassendeklaration angezeigt werden.It is a compile-time error for the same modifier to appear multiple times in a class declaration.

Die new -Modifizierer ist für geschachtelte Klassen zulässig.The new modifier is permitted on nested classes. Es gibt an, dass die Klasse mit dem gleichen Namen, Blendet einen geerbten Member aus wie in beschrieben der new-Modifizierer.It specifies that the class hides an inherited member by the same name, as described in The new modifier. Es ist ein Fehler während der Kompilierung für die new Modifizierer, um in einer Klassendeklaration angezeigt werden, die nicht auf eine Deklaration der geschachtelten Klasse ist.It is a compile-time error for the new modifier to appear on a class declaration that is not a nested class declaration.

Die public, protected, internal, und private Modifizierern steuern den Zugriff auf die Klasse.The public, protected, internal, and private modifiers control the accessibility of the class. Je nach Kontext, in der Deklaration der Klasse steht, einige dieser Modifizierer kann nicht gestattet (deklariert Barrierefreiheit).Depending on the context in which the class declaration occurs, some of these modifiers may not be permitted (Declared accessibility).

Die abstract, sealed und static Modifizierer werden in den folgenden Abschnitten erläutert.The abstract, sealed and static modifiers are discussed in the following sections.

Abstrakte KlassenAbstract classes

Die abstract Modifizierer wird verwendet, um anzugeben, dass eine Klasse unvollständig ist und es wird nur als Basisklasse verwendet werden soll.The abstract modifier is used to indicate that a class is incomplete and that it is intended to be used only as a base class. Eine abstrakte Klasse unterscheidet sich von einer nicht abstrakten Klasse gibt folgenden Möglichkeiten:An abstract class differs from a non-abstract class in the following ways:

  • Eine abstrakte Klasse kann nicht direkt instanziiert werden, und es ist ein Fehler während der Kompilierung mit der new Operator für eine abstrakte Klasse.An abstract class cannot be instantiated directly, and it is a compile-time error to use the new operator on an abstract class. Es ist, zwar möglich, Variablen und Werte, deren Typen während der Kompilierung abstrakt sind diesen Variablen und Werten handelt es sich entweder unbedingt null oder enthält Verweise auf Instanzen von nicht abstrakte Klassen, die von der abstrakten Typen abgeleitet.While it is possible to have variables and values whose compile-time types are abstract, such variables and values will necessarily either be null or contain references to instances of non-abstract classes derived from the abstract types.
  • Eine abstrakte Klasse ist zulässig (jedoch nicht erforderlich) abstrakte Member enthalten.An abstract class is permitted (but not required) to contain abstract members.
  • Eine abstrakte Klasse kann nicht versiegelt werden.An abstract class cannot be sealed.

Wenn eine nicht abstrakte Klasse von einer abstrakten Klasse abgeleitet ist, muss der nicht abstrakten Klasse Implementierungen aller geerbten abstrakten Member, und überschreiben die abstrakte Member enthalten.When a non-abstract class is derived from an abstract class, the non-abstract class must include actual implementations of all inherited abstract members, thereby overriding those abstract members. Im BeispielIn the example

abstract class A
{
    public abstract void F();
}

abstract class B: A
{
    public void G() {}
}

class C: B
{
    public override void F() {
        // actual implementation of F
    }
}

die abstrakte Klasse A stellt eine abstrakte Methode F.the abstract class A introduces an abstract method F. Klasse B führt eine zusätzliche Methode G, da es eine Implementierung bereitstellen, nicht jedoch F, B muss auch als abstrakt deklariert werden.Class B introduces an additional method G, but since it doesn't provide an implementation of F, B must also be declared abstract. Klasse C überschreibt F und eine tatsächliche Implementierung bereitstellt.Class C overrides F and provides an actual implementation. Da es sich um keine abstrakten Member in C, C ist zulässig (jedoch nicht erforderlich), der nicht abstrakt ist.Since there are no abstract members in C, C is permitted (but not required) to be non-abstract.

Versiegelte KlassenSealed classes

Die sealed Modifizierer wird verwendet, um zu verhindern, dass bei der Ableitung von einer Klasse.The sealed modifier is used to prevent derivation from a class. Ein Fehler während der Kompilierung tritt auf, wenn eine versiegelte Klasse als Basisklasse einer anderen Klasse angegeben wird.A compile-time error occurs if a sealed class is specified as the base class of another class.

Eine versiegelte Klasse darf nicht auch eine abstrakte Klasse sein.A sealed class cannot also be an abstract class.

Die sealed Modifizierer wird in erster Linie zum Verhindern von unbeabsichtigten ableitungen, aber sie können zudem bestimmte Optimierungen für die Laufzeit.The sealed modifier is primarily used to prevent unintended derivation, but it also enables certain run-time optimizations. Insbesondere, da eine versiegelte Klasse alle abgeleiteten Klassen nie damit bekannt ist, ist es möglich, eine virtuelle Funktion, die von Memberaufrufen für versiegelte Klasse-Instanzen in nicht-virtuelle Aufrufe zu transformieren.In particular, because a sealed class is known to never have any derived classes, it is possible to transform virtual function member invocations on sealed class instances into non-virtual invocations.

Statische KlassenStatic classes

Die static Modifizierer wird verwendet, um die Klasse deklariert wird, als Markieren einer statische Klasse.The static modifier is used to mark the class being declared as a static class. Eine statische Klasse kann nicht instanziiert werden, kann nicht als Typ verwendet werden und kann nur statische Member enthalten.A static class cannot be instantiated, cannot be used as a type and can contain only static members. Nur eine statische Klasse Deklarationen von Erweiterungsmethoden enthalten kann (Erweiterungsmethoden).Only a static class can contain declarations of extension methods (Extension methods).

Eine statische Klasse-Deklaration ist jedoch mit folgenden Einschränkungen:A static class declaration is subject to the following restrictions:

  • Eine statische Klasse enthält möglicherweise keine sealed oder abstract Modifizierer.A static class may not include a sealed or abstract modifier. Beachten Sie jedoch, da eine statische Klasse kann nicht instanziiert oder abgeleitet werden, verhält sich als wäre es versiegelt und abstrakt.Note, however, that since a static class cannot be instantiated or derived from, it behaves as if it was both sealed and abstract.
  • Eine statische Klasse enthält möglicherweise keine Class_base Spezifikation (Klasse basisspezifizierung) und nicht explizit angeben, eine Basisklasse oder eine Liste der implementierten Schnittstellen.A static class may not include a class_base specification (Class base specification) and cannot explicitly specify a base class or a list of implemented interfaces. Eine statische Klasse erbt implizit vom Typ object.A static class implicitly inherits from type object.
  • Eine statische Klasse kann nur statische Member enthalten (statische und Instanzmember).A static class can only contain static members (Static and instance members). Beachten Sie, dass Konstanten und geschachtelte Typen als statische Member klassifiziert sind.Note that constants and nested types are classified as static members.
  • Eine statische Klasse sind keine Elemente mit protected oder protected internal Barrierefreiheit deklariert.A static class cannot have members with protected or protected internal declared accessibility.

Es ist ein Fehler während der Kompilierung, diese Einschränkungen zu verletzen.It is a compile-time error to violate any of these restrictions.

Eine statische Klasse verfügt über keine Instanzkonstruktoren.A static class has no instance constructors. Es ist nicht möglich, Deklaration eines Instanzkonstruktors in einer statischen Klasse und kein Standardkonstruktor für die Instanz (Standardkonstruktoren) wird bereitgestellt, um eine statische Klasse.It is not possible to declare an instance constructor in a static class, and no default instance constructor (Default constructors) is provided for a static class.

Die Member einer statischen Klasse sind nicht automatisch statisch, und die Memberdeklarationen müssen explizit eine static Modifizierer (mit Ausnahme von Konstanten und geschachtelte Typen).The members of a static class are not automatically static, and the member declarations must explicitly include a static modifier (except for constants and nested types). Wenn eine Klasse in einer statischen äußeren Klasse geschachtelt ist, die geschachtelte Klasse ist keine statische Klasse, sofern es explizit enthält eine static Modifizierer.When a class is nested within a static outer class, the nested class is not a static class unless it explicitly includes a static modifier.

Statische Klasse VerweistypenReferencing static class types

Ein Namespace_or_type_name (Namespace und Typnamen) ist auf eine statische Klasse verweisen, wenn zulässigA namespace_or_type_name (Namespace and type names) is permitted to reference a static class if

  • Die Namespace_or_type_name ist die T in einem Namespace_or_type_name des Formulars T.I, oderThe namespace_or_type_name is the T in a namespace_or_type_name of the form T.I, or
  • Die Namespace_or_type_name ist die T in einem Typeof_expression (Argumentlisten1) des Formulars typeof(T).The namespace_or_type_name is the T in a typeof_expression (Argument lists1) of the form typeof(T).

Ein Primary_expression (Funktionsmember) ist auf eine statische Klasse verweisen, wenn zulässigA primary_expression (Function members) is permitted to reference a static class if

In einem anderen Kontext ist es ein Fehler während der Kompilierung, um auf eine statische Klasse verweisen.In any other context it is a compile-time error to reference a static class. Es ist z. B. einen Fehler für eine statische Klasse als eine Basisklasse, die einen einzelnen Typ verwendet werden soll (geschachtelte Typen) ein Element, ein generisches Typargument oder eine Einschränkung für einen Parameter.For example, it is an error for a static class to be used as a base class, a constituent type (Nested types) of a member, a generic type argument, or a type parameter constraint. Ebenso eine statische Klasse kann nicht in einen Arraytyp, ein Zeigertyp verwendet werden kann eine new Ausdruck, der ein Cast-Ausdruck, ein is Ausdruck eine as Ausdruck eine sizeof Ausdruck oder eine Default-Wertausdruck.Likewise, a static class cannot be used in an array type, a pointer type, a new expression, a cast expression, an is expression, an as expression, a sizeof expression, or a default value expression.

Ein partial-ModifiziererPartial modifier

Die partial Modifizierer verwendet, um anzugeben, das von diesem Class_declaration ist eine Deklaration der partiellen Typ.The partial modifier is used to indicate that this class_declaration is a partial type declaration. Mehrere partielle Typdeklarationen mit dem gleichen Namen in einer einschließenden Namespace oder Typ Deklaration kombiniert werden, um eine Typdeklaration Form, in angegebenen gemäß den Regeln partielle Typen.Multiple partial type declarations with the same name within an enclosing namespace or type declaration combine to form one type declaration, following the rules specified in Partial types.

Müssen die Deklaration einer Klasse, die über separate Segmente des Programmtexts verteilt kann nützlich sein, wenn diese Segmente erstellt oder in unterschiedlichen Kontexten verwaltet werden.Having the declaration of a class distributed over separate segments of program text can be useful if these segments are produced or maintained in different contexts. Z. B. möglicherweise ein Teil einer Klassendeklaration generiert, Computer, während die andere manuell erstellt wird.For instance, one part of a class declaration may be machine generated, whereas the other is manually authored. Text Trennung zwischen den beiden verhindert, dass Updates von einem von in Konflikt stehende mit Updates von anderen.Textual separation of the two prevents updates by one from conflicting with updates by the other.

TypparameterType parameters

Ein Typparameter ist ein einfacher Bezeichner, der einen Platzhalter für ein Typargument, das zum Erstellen eines konstruierten Typs bezeichnet.A type parameter is a simple identifier that denotes a placeholder for a type argument supplied to create a constructed type. Ein Typparameter ist eine formale Platzhalter für einen Typ, der später angegeben werden, wird.A type parameter is a formal placeholder for a type that will be supplied later. Im Gegensatz dazu ein Typargument (Typargumente) ist der tatsächliche Typ, der für den Typparameter ersetzt wird, wenn ein konstruierter Typ erstellt wird.By contrast, a type argument (Type arguments) is the actual type that is substituted for the type parameter when a constructed type is created.

type_parameter_list
    : '<' type_parameters '>'
    ;

type_parameters
    : attributes? type_parameter
    | type_parameters ',' attributes? type_parameter
    ;

type_parameter
    : identifier
    ;

Jeden Typparameter in einer Klassendeklaration definiert einen Namen im Deklarationsbereich (Deklarationen) dieser Klasse.Each type parameter in a class declaration defines a name in the declaration space (Declarations) of that class. Also, es kann nicht den gleichen Namen wie ein anderer Typparameter aufweisen oder ein Member, die in dieser Klasse deklariert.Thus, it cannot have the same name as another type parameter or a member declared in that class. Ein Typparameter kann nicht den gleichen Namen wie der Typ selbst aufweisen.A type parameter cannot have the same name as the type itself.

Die Basisspezifikationen KlasseClass base specification

Eine Klassendeklaration enthalten möglicherweise eine Class_base -Spezifikation, die die direkte Basisklasse der Klasse und die Schnittstellen definiert (Schnittstellen) direkt von der Klasse implementiert.A class declaration may include a class_base specification, which defines the direct base class of the class and the interfaces (Interfaces) directly implemented by the class.

class_base
    : ':' class_type
    | ':' interface_type_list
    | ':' class_type ',' interface_type_list
    ;

interface_type_list
    : interface_type (',' interface_type)*
    ;

Die Basisklasse, die in einer Klassendeklaration angegeben, kann ein konstruierten Klasse-Typ sein (Typen konstruiert).The base class specified in a class declaration can be a constructed class type (Constructed types). Eine Basisklasse darf nicht Typparameter in ihren eigenen sein, obwohl er die Typparameter umfassen kann, die im Gültigkeitsbereich befinden.A base class cannot be a type parameter on its own, though it can involve the type parameters that are in scope.

class Extend<V>: V {}            // Error, type parameter used as base class

BasisklassenBase classes

Wenn eine Class_type befindet sich auf die Class_base, wird die direkte Basisklasse der Klasse deklariert wird.When a class_type is included in the class_base, it specifies the direct base class of the class being declared. Wenn eine Deklaration der Klasse keine Class_base, oder wenn die Class_base Listen nur Schnittstellentypen, die direkte Basisklasse wird als object.If a class declaration has no class_base, or if the class_base lists only interface types, the direct base class is assumed to be object. Eine Klasse erbt von der direkten Basisklasse, Member, wie in beschrieben Vererbung.A class inherits members from its direct base class, as described in Inheritance.

Im BeispielIn the example

class A {}

class B: A {}

Klasse A heißt es, die direkte Basisklasse von B, und B gilt als abgeleitet werden A.class A is said to be the direct base class of B, and B is said to be derived from A. Da A ist keine direkte Basisklasse nicht explizit angeben, die direkte Basisklasse ist implizit object.Since A does not explicitly specify a direct base class, its direct base class is implicitly object.

Für einen konstruierten Klasse, wenn eine Basisklasse in der generischen Klassendeklaration angegeben ist die Basisklasse des konstruierten Typs wird abgerufen, indem ersetzen, für die einzelnen Type_parameter in der entsprechenden Basisklassendeklaration Type_argument des konstruierten Typs.For a constructed class type, if a base class is specified in the generic class declaration, the base class of the constructed type is obtained by substituting, for each type_parameter in the base class declaration, the corresponding type_argument of the constructed type. Erhalten die generische KlassendeklarationenGiven the generic class declarations

class B<U,V> {...}

class G<T>: B<string,T[]> {...}

die Basisklasse des konstruierten Typs G<int> wäre B<string,int[]>.the base class of the constructed type G<int> would be B<string,int[]>.

Die direkte Basisklasse eines Klassentyps muss mindestens dieselben zugriffsmöglichkeiten wie der Klassentyp selbst bieten (Barrierefreiheit Domänen).The direct base class of a class type must be at least as accessible as the class type itself (Accessibility domains). Es ist z. B. ein Fehler während der Kompilierung für eine public Klasse abgeleitet eine private oder internal Klasse.For example, it is a compile-time error for a public class to derive from a private or internal class.

Die direkte Basisklasse eines Klassentyps muss keine der folgenden Typen sein: System.Array, System.Delegate, System.MulticastDelegate, System.Enum, oder System.ValueType.The direct base class of a class type must not be any of the following types: System.Array, System.Delegate, System.MulticastDelegate, System.Enum, or System.ValueType. Darüber hinaus Deklaration einer generischen Klasse können keine System.Attribute als eine direkte oder indirekte Basisklasse.Furthermore, a generic class declaration cannot use System.Attribute as a direct or indirect base class.

Beim Bestimmen der Bedeutung der direkten Basisklasse-Spezifikation A einer Klasse B, die direkte Basisklasse von B wird vorübergehend als object.While determining the meaning of the direct base class specification A of a class B, the direct base class of B is temporarily assumed to be object. Intuitiv Dadurch wird sichergestellt, dass die Bedeutung einer basisklassenspezifikation rekursiv kann nicht auf sich selbst abhängig sind.Intuitively this ensures that the meaning of a base class specification cannot recursively depend on itself. Beispiel:The example:

class A<T> {
   public class B {}
}

class C : A<C.B> {}

ist fehlerhaft. seit in der Basisklasse-Spezifikation A<C.B> die direkte Basisklasse von C gilt object, und somit (durch die Regeln zur Namespace und Typnamen) C nicht gilt kein Element B.is in error since in the base class specification A<C.B> the direct base class of C is considered to be object, and hence (by the rules of Namespace and type names) C is not considered to have a member B.

Die Basisklassen eines Klassentyps sind die direkte Basisklasse und ihre Basisklassen.The base classes of a class type are the direct base class and its base classes. Das heißt, ist die Reihe von Basisklassen den transitiven Abschluss von der direkten basisklassenbeziehung.In other words, the set of base classes is the transitive closure of the direct base class relationship. Wie im Beispiel oben die Basisklassen B sind A und object.Referring to the example above, the base classes of B are A and object. Im BeispielIn the example

class A {...}

class B<T>: A {...}

class C<T>: B<IComparable<T>> {...}

class D<T>: C<T[]> {...}

die Basisklassen D<int> sind C<int[]>, B<IComparable<int[]>>, A, und object.the base classes of D<int> are C<int[]>, B<IComparable<int[]>>, A, and object.

Mit Ausnahme der Klasse object, jeder Klassentyp verfügt über genau eine direkte Basisklasse.Except for class object, every class type has exactly one direct base class. Die object Klasse hat keine direkte Basisklasse und ist die ultimative Basisklasse aller anderen Klassen.The object class has no direct base class and is the ultimate base class of all other classes.

Wenn eine Klasse B leitet sich von einer Klasse A, es ist ein Fehler während der Kompilierung für A hängt B.When a class B derives from a class A, it is a compile-time error for A to depend on B. Eine Klasse hängt direkt von seine direkte Basisklasse (sofern vorhanden) und hängt direkt von der Klasse, in dem es sofort geschachtelt ist (sofern vorhanden).A class directly depends on its direct base class (if any) and directly depends on the class within which it is immediately nested (if any). Dank dieser der vollständige Satz von Klassen, die von dem eine Klasse abhängig ist, wird den reflexiv und transitiv Abschluss von der hängt direkt von Beziehung.Given this definition, the complete set of classes upon which a class depends is the reflexive and transitive closure of the directly depends on relationship.

Im BeispielThe example

class A: A {}

ist fehlerhaft, da die Klasse von sich selbst abhängig ist.is erroneous because the class depends on itself. Ebenso, BeispielLikewise, the example

class A: B {}
class B: C {}
class C: A {}

ist fehlerhaft, da die Klassen zirkulär voneinander abhängig.is in error because the classes circularly depend on themselves. Zum Schluss das BeispielFinally, the example

class A: B.C {}

class B: A
{
    public class C {}
}

führt zu einem Kompilierzeitfehler, da A hängt B.C (seine direkte Basisklasse), abhängig vom B (der unmittelbar einschließenden Klasse), zirkulär abhängig vom A.results in a compile-time error because A depends on B.C (its direct base class), which depends on B (its immediately enclosing class), which circularly depends on A.

Beachten Sie, dass eine Klasse nicht von den Klassen abhängt, die darin geschachtelt sind.Note that a class does not depend on the classes that are nested within it. Im BeispielIn the example

class A
{
    class B: A {}
}

B hängt von A (da A ist seine direkte Basisklasse und die Sie unmittelbar umschließende Klasse), aber A hängt nicht B (da B ist weder eine Basisklasse als auch von einer einschließenden Klasse A ).B depends on A (because A is both its direct base class and its immediately enclosing class), but A does not depend on B (since B is neither a base class nor an enclosing class of A). Im Beispiel ist daher gültig.Thus, the example is valid.

Es ist nicht möglich, für die Ableitung einer sealed Klasse.It is not possible to derive from a sealed class. Im BeispielIn the example

sealed class A {}

class B: A {}            // Error, cannot derive from a sealed class

Klasse B ist falsch, weil er versucht, für die Ableitung der sealed Klasse A.class B is in error because it attempts to derive from the sealed class A.

SchnittstellenimplementierungenInterface implementations

Ein Class_base möglicherweise eine Spezifikation enthalten eine Liste der Schnittstellentypen, in dem Fall die Klasse wird als die angegebene Schnittstelle-Typen direkt zu implementieren.A class_base specification may include a list of interface types, in which case the class is said to directly implement the given interface types. Schnittstellenimplementierungen finden Sie weiter unten in Schnittstellenimplementierungen.Interface implementations are discussed further in Interface implementations.

Einschränkungen für TypparameterType parameter constraints

Generische Typ- und Methodendeklarationen können optional die Einschränkungen für Typparameter angeben, indem einschließlich Type_parameter_constraints_clauses.Generic type and method declarations can optionally specify type parameter constraints by including type_parameter_constraints_clauses.

type_parameter_constraints_clause
    : 'where' type_parameter ':' type_parameter_constraints
    ;

type_parameter_constraints
    : primary_constraint
    | secondary_constraints
    | constructor_constraint
    | primary_constraint ',' secondary_constraints
    | primary_constraint ',' constructor_constraint
    | secondary_constraints ',' constructor_constraint
    | primary_constraint ',' secondary_constraints ',' constructor_constraint
    ;

primary_constraint
    : class_type
    | 'class'
    | 'struct'
    ;

secondary_constraints
    : interface_type
    | type_parameter
    | secondary_constraints ',' interface_type
    | secondary_constraints ',' type_parameter
    ;

constructor_constraint
    : 'new' '(' ')'
    ;

Jede Type_parameter_constraints_clause besteht aus dem Token where, gefolgt vom Namen eines Typparameters, gefolgt von einem Doppelpunkt und die Liste der Einschränkungen für den Typparameter.Each type_parameter_constraints_clause consists of the token where, followed by the name of a type parameter, followed by a colon and the list of constraints for that type parameter. Es kann höchstens eine where -Klausel für jeden Typparameter, und die where Klauseln können in beliebiger Reihenfolge aufgeführt werden.There can be at most one where clause for each type parameter, and the where clauses can be listed in any order. Wie die get und set Token in einem Eigenschaftenaccessor der where Token ist kein Schlüsselwort.Like the get and set tokens in a property accessor, the where token is not a keyword.

Die Liste der Einschränkungen, die im angegebenen ein where -Klausel kann eine der folgenden Komponenten, in der angegebenen Reihenfolge enthalten: eine einzelne primary-Einschränkung, einer oder mehreren sekundären Einschränkungen und die Konstruktoreinschränkung new().The list of constraints given in a where clause can include any of the following components, in this order: a single primary constraint, one or more secondary constraints, and the constructor constraint, new().

Eine primary-Einschränkung kann ein Klassentyp sein oder die verweisen auf eine Einschränkung class oder Wert typeinschränkung struct.A primary constraint can be a class type or the reference type constraint class or the value type constraint struct. Eine sekundäre Einschränkung möglich einen Type_parameter oder Interface_type.A secondary constraint can be a type_parameter or interface_type.

Der verweistypeinschränkung gibt an, dass ein Typargument verwendet, für den Typparameter ein Verweistyp sein muss.The reference type constraint specifies that a type argument used for the type parameter must be a reference type. Alle Klassentypen, Schnittstellentypen, Delegattypen, Arraytypen und Parameter vom Typ bekannt, dass ein Verweistyp (wie unten definiert) werden diese Einschränkung zu erfüllen.All class types, interface types, delegate types, array types, and type parameters known to be a reference type (as defined below) satisfy this constraint.

Der werttypeinschränkung gibt an, dass ein Typargument verwendet, für den Parameter ein NULL-Wert sein muss.The value type constraint specifies that a type argument used for the type parameter must be a non-nullable value type. Alle NULL-Strukturtypen, Enumerationstypen und Parameter vom Typ der werttypeinschränkung müssen diese Einschränkung zu erfüllen.All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. Beachten Sie, dass, obwohl Sie als ein Werttyp, der einen nullable-Typ klassifiziert (auf NULL festlegbare Typen) erfüllt nicht der werttypeinschränkung.Note that although classified as a value type, a nullable type (Nullable types) does not satisfy the value type constraint. Ein Typparameter mit der werttypeinschränkung keine auch die Constructor_constraint.A type parameter having the value type constraint cannot also have the constructor_constraint.

Zeigertypen dürfen keine Typargumente werden und gelten nicht als entweder die Referenz Typ oder Wert typeinschränkungen.Pointer types are never allowed to be type arguments and are not considered to satisfy either the reference type or value type constraints.

Wenn eine Einschränkung eines Klassentyps, einen Schnittstellentyp aufweisen oder ein Typparameter ist, gibt dieses Typs ein minimaler "Basistyp", die jedes Typargument, das für den Typparameter verwendete unterstützen muss.If a constraint is a class type, an interface type, or a type parameter, that type specifies a minimal "base type" that every type argument used for that type parameter must support. Wenn es sich bei einem konstruierten Typ oder eine generische Methode verwendet wird, wird das Typargument für die Einschränkungen für den Typparameter zum Zeitpunkt der Kompilierung überprüft.Whenever a constructed type or generic method is used, the type argument is checked against the constraints on the type parameter at compile-time. Das Typargument muss die in beschriebenen Bedingungen erfüllen, Einschränkungen erfüllen.The type argument supplied must satisfy the conditions described in Satisfying constraints.

Ein Class_type Einschränkung muss die folgenden Regeln entsprechen:A class_type constraint must satisfy the following rules:

  • Der Typ muss ein Klassentyp sein.The type must be a class type.
  • Der Typ muss nicht sealed.The type must not be sealed.
  • Der Typ muss nicht einer der folgenden Typen sein: System.Array, System.Delegate, System.Enum, oder System.ValueType.The type must not be one of the following types: System.Array, System.Delegate, System.Enum, or System.ValueType.
  • Der Typ muss nicht object.The type must not be object. Da alle Typen abgeleitet object, eine solche Einschränkung hätte keine Auswirkung, wenn sie zulässig wären.Because all types derive from object, such a constraint would have no effect if it were permitted.
  • Maximal eine Einschränkung für einen bestimmten Typ-Parameter kann ein Klassentyp sein.At most one constraint for a given type parameter can be a class type.

Ein Typ, der als ein Interface_type Einschränkung muss die folgenden Regeln entsprechen:A type specified as an interface_type constraint must satisfy the following rules:

  • Der Typ muss ein Schnittstellentyp sein.The type must be an interface type.
  • Ein Typ nicht angegeben werden mehr als einmal einer angegebenen where Klausel.A type must not be specified more than once in a given where clause.

In beiden Fällen die Einschränkung kann einer der Typparameter des zugeordneten Typs oder der Deklaration der Methode als Teil eines konstruierten Typs umfassen, und kann den deklarierenden Typ umfassen.In either case, the constraint can involve any of the type parameters of the associated type or method declaration as part of a constructed type, and can involve the type being declared.

Jede Klasse oder Schnittstelle-Typ angegeben wird, eine Einschränkung für einen Parameter muss mindestens dieselben Zugriffstypen unterstützt werden (Barrierefreiheit Einschränkungen) als generischen Typ oder Methode, die deklariert wird.Any class or interface type specified as a type parameter constraint must be at least as accessible (Accessibility constraints) as the generic type or method being declared.

Ein Typ, der als ein Type_parameter Einschränkung muss die folgenden Regeln entsprechen:A type specified as a type_parameter constraint must satisfy the following rules:

  • Der Typ muss es sich um ein Typparameter sein.The type must be a type parameter.
  • Ein Typ nicht angegeben werden mehr als einmal einer angegebenen where Klausel.A type must not be specified more than once in a given where clause.

Darüber hinaus muss gibt es keine Zyklen im Abhängigkeitsdiagramm an Typparametern, in dem Abhängigkeit eine transitive Beziehung durch definiert ist:In addition there must be no cycles in the dependency graph of type parameters, where dependency is a transitive relation defined by:

  • Wenn ein Typparameter T dient als Einschränkung für den Typparameter S dann S hängt T.If a type parameter T is used as a constraint for type parameter S then S depends on T.
  • Wenn ein Typparameter S hängt von einem Typparameter T und T hängt von einem Typparameter U dann S hängt von U.If a type parameter S depends on a type parameter T and T depends on a type parameter U then S depends on U.

Wenn diese Beziehung ist, ist es ein Fehler während der Kompilierung für einen Typparameter auf sich selbst (direkt oder indirekt) abhängig sein.Given this relation, it is a compile-time error for a type parameter to depend on itself (directly or indirectly).

Alle Einschränkungen müssen zwischen abhängigen Typparameter konsistent sein.Any constraints must be consistent among dependent type parameters. Wenn der Typparameter S hängt von den Typparameter T dann:If type parameter S depends on type parameter T then:

  • T darf nicht der werttypeinschränkung sein.T must not have the value type constraint. Andernfalls T ist so effektiv versiegelt S möchten, müssen Sie den gleichen Typ wie werden T, beseitigt die Notwendigkeit zwei Typparametern.Otherwise, T is effectively sealed so S would be forced to be the same type as T, eliminating the need for two type parameters.
  • Wenn S hat der werttypeinschränkung T darf keine Class_type Einschränkung.If S has the value type constraint then T must not have a class_type constraint.
  • Wenn S verfügt über eine Class_type Einschränkung A und T verfügt über eine Class_type Einschränkung B darf eine identitätskonvertierung werden oder implizit Verweisen auf die Konvertierung von A zu B oder eine implizite verweiskonvertierung von B zu A.If S has a class_type constraint A and T has a class_type constraint B then there must be an identity conversion or implicit reference conversion from A to B or an implicit reference conversion from B to A.
  • Wenn S hängt auch von Typparameter U und U verfügt über eine Class_type Einschränkung A und T verfügt über eine Class_type Einschränkung B dann vorhanden, eine identitätskonvertierung oder implizite verweiskonvertierung von sein müssen A zu B oder eine implizite verweiskonvertierung von B zu A.If S also depends on type parameter U and U has a class_type constraint A and T has a class_type constraint B then there must be an identity conversion or implicit reference conversion from A to B or an implicit reference conversion from B to A.

Es gilt für S der werttypeinschränkung haben und T der verweistypeinschränkung haben.It is valid for S to have the value type constraint and T to have the reference type constraint. Effektiv begrenzt T zu den Typen System.Object, System.ValueType, System.Enum, und einen beliebigen anderen Schnittstellentyp.Effectively this limits T to the types System.Object, System.ValueType, System.Enum, and any interface type.

Wenn die where -Klausel für einen Typparameter enthält eine Konstruktoreinschränkung (die weist das Format new()), es ist möglich, verwenden Sie die new Operator, um Instanzen des Typs zu erstellen (Objektausdrücke bei der Erstellung).If the where clause for a type parameter includes a constructor constraint (which has the form new()), it is possible to use the new operator to create instances of the type (Object creation expressions). Jeder Typ verwendete Argument für ein Typparameter eine Konstruktoreinschränkung für einen öffentlichen parameterlosen Konstruktor aufweisen muss (von diesem Konstruktor implizit für jeden Werttyp vorhanden) oder ein Typparameter mit der werttypeinschränkung oder Konstruktoreinschränkung (Siehe werden Geben Sie die Einschränkungen für Typparameter Einzelheiten).Any type argument used for a type parameter with a constructor constraint must have a public parameterless constructor (this constructor implicitly exists for any value type) or be a type parameter having the value type constraint or constructor constraint (see Type parameter constraints for details).

Es folgen Beispiele für Einschränkungen:The following are examples of constraints:

interface IPrintable
{
    void Print();
}

interface IComparable<T>
{
    int CompareTo(T value);
}

interface IKeyProvider<T>
{
    T GetKey();
}

class Printer<T> where T: IPrintable {...}

class SortedList<T> where T: IComparable<T> {...}

class Dictionary<K,V>
    where K: IComparable<K>
    where V: IPrintable, IKeyProvider<K>, new()
{
    ...
}

Im folgende Beispiel ist fehlerhaft, da es eine Zirkularität bewirkt, in dem Abhängigkeitsdiagramm der Typparameter dass:The following example is in error because it causes a circularity in the dependency graph of the type parameters:

class Circular<S,T>
    where S: T
    where T: S                // Error, circularity in dependency graph
{
    ...
}

Die folgenden Beispiele veranschaulichen weitere ungültige Situationen:The following examples illustrate additional invalid situations:

class Sealed<S,T>
    where S: T
    where T: struct        // Error, T is sealed
{
    ...
}

class A {...}

class B {...}

class Incompat<S,T>
    where S: A, T
    where T: B                // Error, incompatible class-type constraints
{
    ...
}

class StructWithClass<S,T,U>
    where S: struct, T
    where T: U
    where U: A                // Error, A incompatible with struct
{
    ...
}

Die effektive Basisklasse eines Typparameters T ist wie folgt definiert:The effective base class of a type parameter T is defined as follows:

  • Wenn T besitzt keine primary-Einschränkungen oder Einschränkungen für Typparameter, effektive Basisklasse object.If T has no primary constraints or type parameter constraints, its effective base class is object.
  • Wenn T hat der werttypeinschränkung, ist der effektive Basisklasse System.ValueType.If T has the value type constraint, its effective base class is System.ValueType.
  • Wenn T verfügt über eine Class_type Einschränkung C aber kein Type_parameter Einschränkungen, die effektive Basisklasse ist C.If T has a class_type constraint C but no type_parameter constraints, its effective base class is C.
  • Wenn T hat keine Class_type Einschränkung weist jedoch mindestens eine Type_parameter Einschränkungen, die effektive Basisklasse ist der am stärksten umfasste (Konvertierung aufgehoben Operatoren) in der Menge der effektiven Basisklassen der Type_parameter Einschränkungen.If T has no class_type constraint but has one or more type_parameter constraints, its effective base class is the most encompassed type (Lifted conversion operators) in the set of effective base classes of its type_parameter constraints. Die Konsistenzregeln stellen Sie sicher, dass diese am stärksten umfasste ein Typ vorhanden ist.The consistency rules ensure that such a most encompassed type exists.
  • Wenn T weist sowohl ein Class_type Einschränkung und eine oder mehrere Type_parameter Einschränkungen, die effektive Basisklasse ist der am stärksten umfasste (Konvertierung aufgehoben Operatoren) im Satz bestehend aus dem Class_type Einschränkung T und die effektive Basisklassen seine Type_parameter Einschränkungen.If T has both a class_type constraint and one or more type_parameter constraints, its effective base class is the most encompassed type (Lifted conversion operators) in the set consisting of the class_type constraint of T and the effective base classes of its type_parameter constraints. Die Konsistenzregeln stellen Sie sicher, dass diese am stärksten umfasste ein Typ vorhanden ist.The consistency rules ensure that such a most encompassed type exists.
  • Wenn T der verweistypeinschränkung hat, aber keine Class_type Einschränkungen, die effektive Basisklasse ist object.If T has the reference type constraint but no class_type constraints, its effective base class is object.

Für diese Regeln, wenn T eine Einschränkung wurde V d. h. eine Value_type, verwenden Sie stattdessen den spezifischsten Basistyp V , eine Class_type.For the purpose of these rules, if T has a constraint V that is a value_type, use instead the most specific base type of V that is a class_type. Dies kann in einem explizit angegebenen Einschränkung nie auftreten, aber kann auftreten, wenn die Einschränkungen einer generischen Methode implizit durch einen überschreibenden Deklaration der Methode oder eine explizite Implementierung einer Schnittstellenmethode geerbt werden.This can never happen in an explicitly given constraint, but may occur when the constraints of a generic method are implicitly inherited by an overriding method declaration or an explicit implementation of an interface method.

Diese Regeln stellen sicher, dass die effektive Basisklasse immer ist eine Class_type.These rules ensure that the effective base class is always a class_type.

Die effektive Satz eines Typparameters T ist wie folgt definiert:The effective interface set of a type parameter T is defined as follows:

  • Wenn T hat keine Secondary_constraints, dessen effektive Schnittstelle-Satz ist leer.If T has no secondary_constraints, its effective interface set is empty.
  • Wenn T hat Interface_type Einschränkungen, aber keine Type_parameter Einschränkungen, die effektive Satz ist die Sammlung von Interface_type Einschränkungen.If T has interface_type constraints but no type_parameter constraints, its effective interface set is its set of interface_type constraints.
  • Wenn T hat keine Interface_type weist Einschränkungen jedoch Type_parameter Einschränkungen, die effektive Satz ist die Vereinigung der effektive Schnittstelle Sätze von dessen Type_ Parameter Einschränkungen.If T has no interface_type constraints but has type_parameter constraints, its effective interface set is the union of the effective interface sets of its type_parameter constraints.
  • Wenn T weist sowohl Interface_type Einschränkungen und Type_parameter Einschränkungen, die effektive Satz ist die Vereinigung der einen Satz von Interface_type Einschränkungen und die effektive Schnittstelle Sätze von dessen Type_parameter Einschränkungen.If T has both interface_type constraints and type_parameter constraints, its effective interface set is the union of its set of interface_type constraints and the effective interface sets of its type_parameter constraints.

Ein Typparameter ist bekannt, dass ein Verweistyp sein ist der verweistypeinschränkung hat oder ihre effektiven Basisklasse nicht object oder System.ValueType.A type parameter is known to be a reference type if it has the reference type constraint or its effective base class is not object or System.ValueType.

Werte einen eingeschränkten Typ Parametertyp können verwendet werden, auf die Instanz-Elemente, die durch die Einschränkungen impliziert.Values of a constrained type parameter type can be used to access the instance members implied by the constraints. Im BeispielIn the example

interface IPrintable
{
    void Print();
}

class Printer<T> where T: IPrintable
{
    void PrintOne(T x) {
        x.Print();
    }
}

die Methoden der IPrintable kann aufgerufen werden, direkt auf x da T immer implementieren IPrintable.the methods of IPrintable can be invoked directly on x because T is constrained to always implement IPrintable.

Text der KlasseClass body

Die Class_body einer Klasse definiert die Elemente dieser Klasse.The class_body of a class defines the members of that class.

class_body
    : '{' class_member_declaration* '}'
    ;

Partial types (Partielle Typen)Partial types

Eine Typdeklaration aufgeteilt werden kann, über mehrere partielle Typdeklarationen.A type declaration can be split across multiple partial type declarations. Die Deklaration des Typs wird aus seiner Teile erstellt, wird entsprechend den Regeln in diesem Abschnitt, wonach es als eine einzelne Deklaration während der Rest der Verarbeitung während der Kompilierung und Laufzeit des Programms behandelt wird.The type declaration is constructed from its parts by following the rules in this section, whereupon it is treated as a single declaration during the remainder of the compile-time and run-time processing of the program.

Ein Class_declaration, Struct_declaration oder Interface_declaration eine Deklaration der partiellen Typ darstellt, sofern er enthält eine partial Modifizierer.A class_declaration, struct_declaration or interface_declaration represents a partial type declaration if it includes a partial modifier. partial ist kein Schlüsselwort und dient nur als ein Modifizierer, wenn es angezeigt, unmittelbar vor der eines der Schlüsselwörter wird class, struct oder interface in einer Typdeklaration oder vor dem Typ void in einer Methodendeklaration.partial is not a keyword, and only acts as a modifier if it appears immediately before one of the keywords class, struct or interface in a type declaration, or before the type void in a method declaration. In anderen Kontexten können sie als ein normaler Bezeichner verwendet werden.In other contexts it can be used as a normal identifier.

Jeder Teil einer Deklaration der partiellen Typs muss enthalten eine partial Modifizierer.Each part of a partial type declaration must include a partial modifier. Sie müssen den gleichen Namen aufweisen und in den gleichen Namespace oder die Typdeklaration als die anderen Teile deklariert werden.It must have the same name and be declared in the same namespace or type declaration as the other parts. Die partial Modifizierer gibt an, dass zusätzliche Teile der Typdeklaration möglicherweise an anderer Stelle vorhanden, aber das Vorhandensein von zusätzlichen Komponenten nicht erforderlich ist; es gilt für einen Typ mit einer einzigen Deklaration sollen die partial Modifizierer.The partial modifier indicates that additional parts of the type declaration may exist elsewhere, but the existence of such additional parts is not a requirement; it is valid for a type with a single declaration to include the partial modifier.

Alle Teile eines partiellen Typs müssen zusammen kompiliert werden, sodass Teile zum Zeitpunkt der Kompilierung in eine einzelne Typdeklaration zusammengeführt werden können.All parts of a partial type must be compiled together such that the parts can be merged at compile-time into a single type declaration. Partielle Typen lassen nicht speziell bereits kompilierte Typen erweitert werden soll.Partial types specifically do not allow already compiled types to be extended.

Geschachtelte Typen können aus mehreren Teilen deklariert werden, mithilfe der partial Modifizierer.Nested types may be declared in multiple parts by using the partial modifier. In der Regel wird der enthaltende Typ mit deklariert partial gut, und jeder Teil des geschachtelten Typs in einem anderen Teil des enthaltenden Typs deklariert ist.Typically, the containing type is declared using partial as well, and each part of the nested type is declared in a different part of the containing type.

Die partial Modifizierer ist für Delegat- oder Enum-Deklarationen nicht zulässig.The partial modifier is not permitted on delegate or enum declarations.

AttributeAttributes

Die Attribute eines partiellen Typs werden durch die Kombination von können Sie in einer nicht vorgegebenen Reihenfolge, die Attribute der einzelnen Teile bestimmt.The attributes of a partial type are determined by combining, in an unspecified order, the attributes of each of the parts. Wenn ein Attribut auf mehrere Teile platziert wird, entspricht das Attribut mehrmals für den Typ angegeben.If an attribute is placed on multiple parts, it is equivalent to specifying the attribute multiple times on the type. Beispielsweise die beiden Teile:For example, the two parts:

[Attr1, Attr2("hello")]
partial class A {}

[Attr3, Attr2("goodbye")]
partial class A {}

gibt z. B. eine Deklaration entspricht:are equivalent to a declaration such as:

[Attr1, Attr2("hello"), Attr3, Attr2("goodbye")]
class A {}

Attribute für Typparameter auf ähnliche Weise zu kombinieren.Attributes on type parameters combine in a similar fashion.

ModifiziererModifiers

Wenn eine Deklaration einer partiellen Typ enthält eine Spezifikation für die Barrierefreiheit (die public, protected, internal, und private Modifizierer) sie müssen zustimmen, andere Komponenten, die eine Spezifikation für die Barrierefreiheit enthalten.When a partial type declaration includes an accessibility specification (the public, protected, internal, and private modifiers) it must agree with all other parts that include an accessibility specification. Wenn kein Teil eines partiellen Typs eine Spezifikation für die Barrierefreiheit enthält, wird der Typ der entsprechenden Standardzugriff angegeben (deklariert Barrierefreiheit).If no part of a partial type includes an accessibility specification, the type is given the appropriate default accessibility (Declared accessibility).

Wenn ein oder mehr partielle Deklarationen eines geschachtelten Typs enthalten eine new Modifizierer keine Warnung wird ausgegeben, wenn der geschachtelte Typ einen geerbten Member Blendet (ausblenden, die durch Vererbung von).If one or more partial declarations of a nested type include a new modifier, no warning is reported if the nested type hides an inherited member (Hiding through inheritance).

Wenn eine oder mehrere partielle Deklarationen, die von einer Klasse umfassen eine abstract Modifizierer die Klasse gilt als abstrakt (abstrakte Klassen).If one or more partial declarations of a class include an abstract modifier, the class is considered abstract (Abstract classes). Andernfalls gilt die Klasse abstrakt.Otherwise, the class is considered non-abstract.

Wenn eine oder mehrere partielle Deklarationen, die von einer Klasse enthalten eine sealed Modifizierer die Klasse wird als versiegelt betrachtet (versiegelte Klassen).If one or more partial declarations of a class include a sealed modifier, the class is considered sealed (Sealed classes). Andernfalls gilt die Klasse nicht versiegelten.Otherwise, the class is considered unsealed.

Beachten Sie, dass eine Klasse nicht gleichzeitig abstrakt und versiegelt sein kann.Note that a class cannot be both abstract and sealed.

Wenn die unsafe Modifizierer ist für eine partielle Typdeklaration verwendet, nur diesen bestimmte Teil als unsicherer Kontext angesehen wird (nicht sicheren Kontexten).When the unsafe modifier is used on a partial type declaration, only that particular part is considered an unsafe context (Unsafe contexts).

Typparameter und EinschränkungenType parameters and constraints

Wenn in mehreren Teilen ein generisches Typs deklariert wird, muss jeder Teil die Typparameter angeben.If a generic type is declared in multiple parts, each part must state the type parameters. Jeder Teil muss die gleiche Anzahl von Typparametern und den gleichen Namen für jeden Typparameter in der Reihenfolge haben.Each part must have the same number of type parameters, and the same name for each type parameter, in order.

Wenn eine partielle generischen Typdeklaration enthält Einschränkungen (where Klauseln), die Einschränkungen müssen zustimmen, andere Komponenten, die Einschränkungen enthalten.When a partial generic type declaration includes constraints (where clauses), the constraints must agree with all other parts that include constraints. Insbesondere jeder Teil, der Einschränkungen enthält, müssen Einschränkungen für den gleichen Satz an Typparametern und für jeden Typparameter der Sätze von primären, sekundären und konstruktoreinschränkungen müssen äquivalent sein.Specifically, each part that includes constraints must have constraints for the same set of type parameters, and for each type parameter the sets of primary, secondary, and constructor constraints must be equivalent. Zwei Sätze von Integritätsregeln sind äquivalent, wenn sie dieselben Elemente enthalten.Two sets of constraints are equivalent if they contain the same members. Wenn kein Teil eines partiellen Typs für die generische Einschränkungen für Typparameter angegeben wird, ist kein Hindernis für der Typ, Parameter berücksichtigt werden.If no part of a partial generic type specifies type parameter constraints, the type parameters are considered unconstrained.

Im BeispielThe example

partial class Dictionary<K,V>
    where K: IComparable<K>
    where V: IKeyProvider<K>, IPersistable
{
    ...
}

partial class Dictionary<K,V>
    where V: IPersistable, IKeyProvider<K>
    where K: IComparable<K>
{
    ...
}

partial class Dictionary<K,V>
{
    ...
}

ist richtig, da die Teile, die Einschränkungen (die ersten beiden) effektiv enthalten die gleichen Satz von primären, sekundären und konstruktoreinschränkungen für den gleichen Satz an Typparametern angeben.is correct because those parts that include constraints (the first two) effectively specify the same set of primary, secondary, and constructor constraints for the same set of type parameters, respectively.

BasisklasseBase class

Wenn eine Deklaration der partiellen Klasse eine basisklassenspezifikation enthält müssen sie alle anderen Teile zustimmen, die eine basisklassenspezifikation enthalten.When a partial class declaration includes a base class specification it must agree with all other parts that include a base class specification. Wenn kein Teil einer partiellen Klasse eine basisklassenspezifikation enthält, wird die Basisklasse System.Object (Basisklassen).If no part of a partial class includes a base class specification, the base class becomes System.Object (Base classes).

BasisschnittstellenBase interfaces

Der Satz von Schnittstellen für einen Typ, der aus mehreren Teilen deklariert ist die Union der Basisschnittstellen für jede Komponente angegeben.The set of base interfaces for a type declared in multiple parts is the union of the base interfaces specified on each part. Eine bestimmte Basis-Schnittstelle kann nur einmal für jede Komponente namens werden, aber es ist zulässig, für mehrere Teile, benennen Sie die gleichen basisschnitstelle.A particular base interface may only be named once on each part, but it is permitted for multiple parts to name the same base interface(s). Es muss nur eine Implementierung der Elemente einer angegebenen Basis-Schnittstelle vorhanden sein.There must only be one implementation of the members of any given base interface.

Im BeispielIn the example

partial class C: IA, IB {...}

partial class C: IC {...}

partial class C: IA, IB {...}

der Satz von Schnittstellen für die Klasse C ist IA, IB, und IC.the set of base interfaces for class C is IA, IB, and IC.

In der Regel stellt jeder Teil eine Implementierung der Schnittstellen, die für diesen Teil deklariert; Dies ist jedoch keine Voraussetzung.Typically, each part provides an implementation of the interface(s) declared on that part; however, this is not a requirement. Ein Teil kann die Implementierung einer Schnittstelle deklariert, die auf einem anderen Teil bereitstellen:A part may provide the implementation for an interface declared on a different part:

partial class X
{
    int IComparable.CompareTo(object o) {...}
}

partial class X: IComparable
{
    ...
}

MemberMembers

Mit Ausnahme von partiellen Methoden (partielle Methoden), die Menge der Elemente eines Typs, die in mehreren Teilen deklariert ist, einfach die Vereinigung der Menge der Elemente in jedem Teil deklariert.With the exception of partial methods (Partial methods), the set of members of a type declared in multiple parts is simply the union of the set of members declared in each part. Die Texte der alle Teile der Typdeklaration Freigabe im selben Deklarationsabschnitt (Deklarationen), und der Bereich für jedes Element (Bereiche) erstreckt sich auch auf die Texte der alle Teile.The bodies of all parts of the type declaration share the same declaration space (Declarations), and the scope of each member (Scopes) extends to the bodies of all the parts. Die Zugriffsdomäne eines Members enthält immer alle Teile des einschließenden Typs; eine private in einem Bereich deklarierten Member aus einem anderen Teil frei zugänglich ist.The accessibility domain of any member always includes all the parts of the enclosing type; a private member declared in one part is freely accessible from another part. Es ist ein Fehler während der Kompilierung, um dasselbe Element in mehr als ein Teil des Typs zu deklarieren, es sei denn, dieser Member ein Typ mit ist der partial Modifizierer.It is a compile-time error to declare the same member in more than one part of the type, unless that member is a type with the partial modifier.

partial class A
{
    int x;                     // Error, cannot declare x more than once

    partial class Inner        // Ok, Inner is a partial type
    {
        int y;
    }
}

partial class A
{
    int x;                     // Error, cannot declare x more than once

    partial class Inner        // Ok, Inner is a partial type
    {
        int z;
    }
}

Die Reihenfolge der Elemente in einem Typ wird nur selten relevant, für die c#-Code, aber kann erheblich sein, wenn für die Kommunikation mit anderen Sprachen und Umgebungen.The ordering of members within a type is rarely significant to C# code, but may be significant when interfacing with other languages and environments. In diesen Fällen ist es nicht definiert, die Reihenfolge der Member innerhalb eines Typs, die in mehreren Teilen deklariert.In these cases, the ordering of members within a type declared in multiple parts is undefined.

Partielle MethodenPartial methods

Partielle Methoden in einem Teil einer Typdeklaration definiert, und in einem anderen implementiert werden können.Partial methods can be defined in one part of a type declaration and implemented in another. Die Implementierung ist optional. Wenn kein Teil die partielle Methode implementiert, werden die Deklaration der partiellen Methode und alle Aufrufe aus die Typdeklaration, die durch die Kombination aus den Teilen entfernt.The implementation is optional; if no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts.

Partielle Methoden können keine Zugriffsmodifizierer definieren, jedoch handelt es sich implizit private.Partial methods cannot define access modifiers, but are implicitly private. Ihren Rückgabetyp muss void, und ihre Parameter darf keine der out Modifizierer.Their return type must be void, and their parameters cannot have the out modifier. Der Bezeichner partial wird als eine spezielle Schlüsselwort in einer Methodendeklaration erkannt, nur, wenn Sie anscheinend direkt vor der void geben; andernfalls kann es als ein normaler Bezeichner verwendet werden.The identifier partial is recognized as a special keyword in a method declaration only if it appears right before the void type; otherwise it can be used as a normal identifier. Eine partielle Methode kann keine Schnittstellenmethoden explizit implementieren.A partial method cannot explicitly implement interface methods.

Es gibt zwei Arten von Deklarationen der partiellen Methode ein: Wenn der Hauptteil der Deklaration der Methode ein Semikolon ist, die Deklaration wird als eine definierende Deklaration der partiellen Methode.There are two kinds of partial method declarations: If the body of the method declaration is a semicolon, the declaration is said to be a defining partial method declaration. Wenn Text, als angegeben wird eine Block, die Deklaration wird als ein implementierende Deklaration der partiellen Methode.If the body is given as a block, the declaration is said to be an implementing partial method declaration. Für die Teile einer Typdeklaration es kann nur eine definierende Deklaration der partiellen Methode mit einem angegebenen Signatur-, und es kann nur eine implementierende Deklaration der partiellen Methode mit einer bestimmten Signatur.Across the parts of a type declaration there can be only one defining partial method declaration with a given signature, and there can be only one implementing partial method declaration with a given signature. Wenn eine implementierende Deklaration der partiellen Methode angegeben, eine entsprechende definierende Deklaration der partiellen Methode vorhanden sein muss und müssen die Deklarationen als übereinstimmen, die in der folgenden angegeben werden:If an implementing partial method declaration is given, a corresponding defining partial method declaration must exist, and the declarations must match as specified in the following:

  • Die Deklarationen müssen die gleichen Modifizierer (obwohl nicht unbedingt in der gleichen Reihenfolge), Methodennamen, der Anzahl von Typparametern und der Anzahl von Parametern.The declarations must have the same modifiers (although not necessarily in the same order), method name, number of type parameters and number of parameters.
  • Entsprechende Parameter in den Deklarationen müssen die gleichen Modifizierer (obwohl nicht unbedingt in der gleichen Reihenfolge) und den gleichen Typ (modulo Unterschiede bei Typparameternamen).Corresponding parameters in the declarations must have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names).
  • Entsprechende Typparameter in den Deklarationen müssen dieselben Einschränkungen (modulo Unterschiede bei Typparameternamen).Corresponding type parameters in the declarations must have the same constraints (modulo differences in type parameter names).

Eine implementierende Deklaration der partiellen Methode kann in den gleichen Teil als entsprechende definierende Deklaration der partiellen Methode erscheinen.An implementing partial method declaration can appear in the same part as the corresponding defining partial method declaration.

Nur eine definierende partielle Methode, die an der überladungsauflösung beteiligt ist.Only a defining partial method participates in overload resolution. Also, und zwar unabhängig davon, ob eine implementierende Deklaration angegeben ist, können auf Aufrufe der partiellen Methode Aufrufausdrücke beheben.Thus, whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. Da eine partielle Methode immer zurückgibt void, solche Aufrufausdrücke werden sich immer auf die Tabellenausdruck-Anweisungen.Because a partial method always returns void, such invocation expressions will always be expression statements. Darüber hinaus, da eine partielle Methode implizit wird private, solche Anweisungen treten immer innerhalb einer der Bestandteile der Typdeklaration, die in dem die partielle Methode deklariert ist.Furthermore, because a partial method is implicitly private, such statements will always occur within one of the parts of the type declaration within which the partial method is declared.

Wenn kein Teil einer Deklaration der partiellen Typ eine implementierende Deklaration für eine bestimmte partielle Methode enthält, wird Ausdrucksanweisung Aufrufen aus der kombinierten Typdeklaration einfach entfernt.If no part of a partial type declaration contains an implementing declaration for a given partial method, any expression statement invoking it is simply removed from the combined type declaration. Daher ist der Aufrufausdruck, einschließlich der enthaltenen Ausdrücke, hat keine Auswirkungen zur Laufzeit.Thus the invocation expression, including any constituent expressions, has no effect at run-time. Die partielle Methode selbst wird wird ebenfalls entfernt und nicht Mitglied der kombinierten Typdeklaration.The partial method itself is also removed and will not be a member of the combined type declaration.

Wenn die implementierende Deklaration für eine bestimmte partielle Methode vorhanden sind, werden die Aufrufe der partiellen Methoden beibehalten.If an implementing declaration exist for a given partial method, the invocations of the partial methods are retained. Die partielle Methode führt zu einer Methodendeklaration, die die implementierende Deklaration der partiellen Methode mit Ausnahme der folgenden ähnelt:The partial method gives rise to a method declaration similar to the implementing partial method declaration except for the following:

  • Die partial Modifizierer nicht enthalten ist.The partial modifier is not included
  • Die Attribute in der resultierenden Methodendeklaration sind die kombinierten Attribute definieren und die implementierende Deklaration der partiellen Methode Erweiterungsvalidierungsmethoden ohne spezifische Reihenfolge.The attributes in the resulting method declaration are the combined attributes of the defining and the implementing partial method declaration in unspecified order. Duplikate werden nicht entfernt.Duplicates are not removed.
  • Die Attribute für die Parameter, der sich ergebenden Methodendeklaration sind der Kombination der Eigenschaften der entsprechenden Parameter definieren und die implementierende Deklaration der partiellen Methode in einer nicht vorgegebenen Reihenfolge.The attributes on the parameters of the resulting method declaration are the combined attributes of the corresponding parameters of the defining and the implementing partial method declaration in unspecified order. Duplikate werden nicht entfernt.Duplicates are not removed.

Wenn eine definierende Deklaration jedoch keine implementierende Deklaration für eine partielle Methode M gegeben wird, gelten die folgenden Einschränkungen:If a defining declaration but not an implementing declaration is given for a partial method M, the following restrictions apply:

Partielle Methoden sind hilfreich für das Zulassen von einem Teil einer Typdeklaration, um das Verhalten von einem anderen Teil, z. B. eine anzupassen, die von einem Tool generiert wird.Partial methods are useful for allowing one part of a type declaration to customize the behavior of another part, e.g., one that is generated by a tool. Beachten Sie die folgende Deklaration der partiellen Klasse ein:Consider the following partial class declaration:

partial class Customer
{
    string name;

    public string Name {
        get { return name; }
        set {
            OnNameChanging(value);
            name = value;
            OnNameChanged();
        }

    }

    partial void OnNameChanging(string newName);

    partial void OnNameChanged();
}

Wenn diese Klasse, ohne auf andere Teile kompiliert wird, die definierende Deklarationen der partiellen Methode und ihre Aufrufe werden entfernt, und die resultierende kombinierten Klassendeklaration werden äquivalent zu folgendem:If this class is compiled without any other parts, the defining partial method declarations and their invocations will be removed, and the resulting combined class declaration will be equivalent to the following:

class Customer
{
    string name;

    public string Name {
        get { return name; }
        set { name = value; }
    }
}

Nehmen Sie an, dass ein anderer Teil, jedoch verfügt die implementierende Deklarationen der partiellen Methoden bereitstellt:Assume that another part is given, however, which provides implementing declarations of the partial methods:

partial class Customer
{
    partial void OnNameChanging(string newName)
    {
        Console.WriteLine("Changing " + name + " to " + newName);
    }

    partial void OnNameChanged()
    {
        Console.WriteLine("Changed to " + name);
    }
}

Anschließend werden die resultierenden kombinierten Klassendeklaration äquivalent zu folgendem:Then the resulting combined class declaration will be equivalent to the following:

class Customer
{
    string name;

    public string Name {
        get { return name; }
        set {
            OnNameChanging(value);
            name = value;
            OnNameChanged();
        }

    }

    void OnNameChanging(string newName)
    {
        Console.WriteLine("Changing " + name + " to " + newName);
    }

    void OnNameChanged()
    {
        Console.WriteLine("Changed to " + name);
    }
}

-BindungenName binding

Obwohl jeder Teil eine erweiterbare Typ in den gleichen Namespace deklariert werden muss, werden die Teile in der Regel in den anderen Namespace-Deklarationen geschrieben.Although each part of an extensible type must be declared within the same namespace, the parts are typically written within different namespace declarations. Daher verschiedene using Directives (Using-Direktiven) kann für die einzelnen Teile vorhanden sein.Thus, different using directives (Using directives) may be present for each part. Beim Interpretieren von einfachen Namen (Typrückschluss) in nur ein Teil der using gelten als Anweisungen von der dieses Teils einschließenden Namespace zurückzusenden.When interpreting simple names (Type inference) within one part, only the using directives of the namespace declaration(s) enclosing that part are considered. Dies kann dazu führen, dass den gleichen Bezeichner müssen verschiedene Bedeutungen in verschiedenen Teilen:This may result in the same identifier having different meanings in different parts:

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

KlassenmemberClass members

Die Member einer Klasse bestehen aus der Elemente eingeführt, durch die Class_member_declarations und die Elemente, die von der direkten Basisklasse geerbt.The members of a class consist of the members introduced by its class_member_declarations and the members inherited from the direct base class.

class_member_declaration
    : constant_declaration
    | field_declaration
    | method_declaration
    | property_declaration
    | event_declaration
    | indexer_declaration
    | operator_declaration
    | constructor_declaration
    | destructor_declaration
    | static_constructor_declaration
    | type_declaration
    ;

Die Member eines Klassentyps sind in folgenden Kategorien unterteilt:The members of a class type are divided into the following categories:

  • Konstanten, die Konstanten Werte, die der Klasse zugeordneten darstellen (Konstanten).Constants, which represent constant values associated with the class (Constants).
  • Felder, die die Variablen der Klasse (Felder).Fields, which are the variables of the class (Fields).
  • Methoden, die Implementierung der Berechnungen und Aktionen, die von der Klasse ausgeführt werden können (Methoden).Methods, which implement the computations and actions that can be performed by the class (Methods).
  • Eigenschaften, die definieren, mit dem Namen Merkmale und der Aktionen in Verbindung mit dem Lesen und Schreiben diese Eigenschaften (Eigenschaften).Properties, which define named characteristics and the actions associated with reading and writing those characteristics (Properties).
  • Ereignisse, die Benachrichtigungen zu definieren, die von der Klasse generiert werden kann (Ereignisse).Events, which define notifications that can be generated by the class (Events).
  • Indexer, die zulassen von Instanzen der Klasse, die auf die gleiche Weise indiziert werden als Arrays (syntaktisch) (Indexer).Indexers, which permit instances of the class to be indexed in the same way (syntactically) as arrays (Indexers).
  • Operatoren, die die Operatoren für Ausdrücke zu definieren, die auf Instanzen der Klasse angewendet werden können (Operatoren).Operators, which define the expression operators that can be applied to instances of the class (Operators).
  • Instanzkonstruktoren, die die erforderlichen Aktionen zum Initialisieren von Instanzen der Klasse zu implementieren (Instanzkonstruktoren)Instance constructors, which implement the actions required to initialize instances of the class (Instance constructors)
  • Destruktoren, die die Aktionen, die ausgeführt werden, bevor Instanzen der Klasse dauerhaft verworfen werden implementieren (Destruktoren).Destructors, which implement the actions to be performed before instances of the class are permanently discarded (Destructors).
  • Statische Konstruktoren, die die erforderlichen Aktionen zum Initialisieren der Klasse selbst zu implementieren (statische Konstruktoren).Static constructors, which implement the actions required to initialize the class itself (Static constructors).
  • Typen, die die Typen darstellen, die lokal auf die Klasse sind (geschachtelte Typen).Types, which represent the types that are local to the class (Nested types).

Elemente, die ausführbaren Code enthalten können, werden zusammen als bezeichnet die Funktionsmember des Klassentyps.Members that can contain executable code are collectively known as the function members of the class type. Die Funktionsmember eines Klassentyps sind die Methoden, Eigenschaften, Ereignisse, Indexer, Operatoren, Instanzkonstruktoren, Destruktoren und statischen Konstruktoren des Klassentyps.The function members of a class type are the methods, properties, events, indexers, operators, instance constructors, destructors, and static constructors of that class type.

Ein Class_declaration erstellt einen neuen Deklarationsabschnitt (Deklarationen), und die Class_member_declarations sofort enthalten die Klasse _declaration neue Elemente in diesen Deklarationsabschnitt einführen.A class_declaration creates a new declaration space (Declarations), and the class_member_declarations immediately contained by the class_declaration introduce new members into this declaration space. Die folgenden Regeln gelten für Class_member_declarations:The following rules apply to class_member_declarations:

  • Instanzkonstruktoren, Destruktoren und statische Konstruktoren müssen den gleichen Namen wie die Sie unmittelbar umschließende Klasse aufweisen.Instance constructors, destructors and static constructors must have the same name as the immediately enclosing class. Alle anderen Elemente müssen Namen haben, die von den Namen der unmittelbar einschließenden Klasse abweichen.All other members must have names that differ from the name of the immediately enclosing class.
  • Der Name der eine Konstante, ein Feld, Eigenschaft, Ereignis oder Typ muss die Namen aller anderen Elemente, die in der gleichen Klasse deklariert unterscheiden.The name of a constant, field, property, event, or type must differ from the names of all other members declared in the same class.
  • Der Name einer Methode muss die Namen aller anderen nicht--Methoden, in der gleichen Klasse deklariert unterscheiden.The name of a method must differ from the names of all other non-methods declared in the same class. Außerdem wird die Signatur (Signaturen und überladen) von eine Methode muss die Signaturen aller anderen in derselben Klasse deklarierten Methoden unterscheiden, und zwei Methoden, die in der gleichen Klasse deklariert dürfen keine Signaturen, die ausschließlich unterscheiden. durch ref und out.In addition, the signature (Signatures and overloading) of a method must differ from the signatures of all other methods declared in the same class, and two methods declared in the same class may not have signatures that differ solely by ref and out.
  • Die Signatur eines Instanzkonstruktors muss von den Signaturen aller anderen in derselben Klasse deklarierten Instanzkonstruktoren unterscheiden, und zwei Konstruktoren, die in der gleichen Klasse deklariert dürfen keine Signaturen, die ausschließlich vom unterscheiden ref und out.The signature of an instance constructor must differ from the signatures of all other instance constructors declared in the same class, and two constructors declared in the same class may not have signatures that differ solely by ref and out.
  • Die Signatur eines Indexers muss die Signaturen aller anderen in derselben Klasse deklarierten Indexer unterscheiden.The signature of an indexer must differ from the signatures of all other indexers declared in the same class.
  • Die Signatur eines Operators muss die Signaturen aller anderen Operatoren, die in der gleichen Klasse deklariert unterscheiden.The signature of an operator must differ from the signatures of all other operators declared in the same class.

Die geerbten Member eines Klassentyps (Vererbung) sind nicht Teil des Speicherplatzes Deklaration einer Klasse.The inherited members of a class type (Inheritance) are not part of the declaration space of a class. Daher kann eine abgeleitete Klasse ein Element mit demselben Namen bzw. derselben Signatur als einen geerbten Member zu deklarieren (d. Blendet die geerbten Member in Kraft).Thus, a derived class is allowed to declare a member with the same name or signature as an inherited member (which in effect hides the inherited member).

Der InstanztypThe instance type

Jede Deklaration der Klasse verfügt über einen zugeordneten gebundenen Typ (gebunden und Typen von nicht gebundenen), wird die Instanztyp.Each class declaration has an associated bound type (Bound and unbound types), the instance type. Für die Deklaration einer generischen Klasse, wird der Instanztyp durch das Erstellen eines konstruierten Typs gebildet (Typen konstruiert) aus der Deklaration des Typs mit den angegebenen Typ Argumente werden den entsprechenden Typparameter.For a generic class declaration, the instance type is formed by creating a constructed type (Constructed types) from the type declaration, with each of the supplied type arguments being the corresponding type parameter. Da der Instanztyp die Typparameter verwendet, können sie nur, in dem sich die Typparameter im Gültigkeitsbereich befinden verwendet werden. d. h. in der Klassendeklaration.Since the instance type uses the type parameters, it can only be used where the type parameters are in scope; that is, inside the class declaration. Der Instanztyp ist der Typ der this für Code in der Klassendeklaration geschrieben wurde.The instance type is the type of this for code written inside the class declaration. Für nicht generische Klassen ist der Instanztyp einfach die deklarierte-Klasse.For non-generic classes, the instance type is simply the declared class. Das folgende Beispiel zeigt mehrere Klassendeklarationen zusammen mit ihren Instanztypen aus:The following shows several class declarations along with their instance types:

class A<T>                           // instance type: A<T>
{
    class B {}                       // instance type: A<T>.B
    class C<U> {}                    // instance type: A<T>.C<U>
}

class D {}                           // instance type: D

Mitglieder der konstruierte TypenMembers of constructed types

Die nicht geerbte Member eines konstruierten Typs erhalten Sie durch Ersetzen der für die einzelnen Type_parameter in der Element-Deklaration wird das entsprechende Type_argument des konstruierten Typs.The non-inherited members of a constructed type are obtained by substituting, for each type_parameter in the member declaration, the corresponding type_argument of the constructed type. Die Ersetzung Prozess basiert auf die semantische Bedeutung der Deklarationen von Typen und ist nicht einfach Text ersetzen.The substitution process is based on the semantic meaning of type declarations, and is not simply textual substitution.

Wenn z. B. die generische Klasse-DeklarationFor example, given the generic class declaration

class Gen<T,U>
{
    public T[,] a;
    public void G(int i, T t, Gen<U,T> gt) {...}
    public U Prop { get {...} set {...} }
    public int H(double d) {...}
}

Der konstruierte Typ Gen<int[],IComparable<string>> hat die folgenden Elemente:the constructed type Gen<int[],IComparable<string>> has the following members:

public int[,][] a;
public void G(int i, int[] t, Gen<IComparable<string>,int[]> gt) {...}
public IComparable<string> Prop { get {...} set {...} }
public int H(double d) {...}

Der Typ des Members a in der generischen Klassendeklaration Gen ist "zweidimensionales Array von T", sodass der Typ des Members a im oben erstellten Typ ist "zweidimensionales Array von eindimensionales Array von int", oder int[,][].The type of the member a in the generic class declaration Gen is "two-dimensional array of T", so the type of the member a in the constructed type above is "two-dimensional array of one-dimensional array of int", or int[,][].

Innerhalb der Funktion Instanzmember, der Typ des this ist der Instanztyp (den Instanztyp) der Deklaration enthält.Within instance function members, the type of this is the instance type (The instance type) of the containing declaration.

Alle Member einer generischen Klasse können Typparameter von einer einschließenden Klasse, entweder direkt oder als Teil eines konstruierten Typs verwenden.All members of a generic class can use type parameters from any enclosing class, either directly or as part of a constructed type. Beim Schließen von einer bestimmtes konstruierten Typ (offene und geschlossene Typen) wird verwendet, zur Laufzeit, wird jede Verwendung von einem Typparameter durch die tatsächliche, für den konstruierten Typ angegebenes Typargument ersetzt.When a particular closed constructed type (Open and closed types) is used at run-time, each use of a type parameter is replaced with the actual type argument supplied to the constructed type. Zum Beispiel:For example:

class C<V>
{
    public V f1;
    public C<V> f2 = null;

    public C(V x) {
        this.f1 = x;
        this.f2 = this;
    }
}

class Application
{
    static void Main() {
        C<int> x1 = new C<int>(1);
        Console.WriteLine(x1.f1);        // Prints 1

        C<double> x2 = new C<double>(3.1415);
        Console.WriteLine(x2.f1);        // Prints 3.1415
    }
}

VererbungInheritance

Eine Klasse erbt die Member dieses Typs direkte Basisklasse.A class inherits the members of its direct base class type. Vererbung bedeutet, dass eine Klasse implizit alle Member seines Typs direkte Basisklasse mit Ausnahme der Instanzkonstruktoren, Destruktoren und statische Konstruktoren der Basisklasse enthält.Inheritance means that a class implicitly contains all members of its direct base class type, except for the instance constructors, destructors and static constructors of the base class. Einige wichtige Aspekte bei der Vererbung sind:Some important aspects of inheritance are:

  • Vererbung ist transitiv.Inheritance is transitive. Wenn C ergibt sich aus B, und B ergibt sich aus A, klicken Sie dann C im deklarierten Member erbt B sowie im deklarierten Member A.If C is derived from B, and B is derived from A, then C inherits the members declared in B as well as the members declared in A.
  • Eine abgeleitete Klasse erweitert seine direkte Basisklasse.A derived class extends its direct base class. Eine abgeleitete Klasse kann den geerbten Membern neue Member hinzufügen, aber die Definition eines geerbten Members kann nicht entfernt werden.A derived class can add new members to those it inherits, but it cannot remove the definition of an inherited member.
  • Instanzkonstruktoren, Destruktoren und statischen Konstruktoren nicht geerbt werden, aber alle anderen Elemente sind, unabhängig von deren deklarierte Zugriffsart (Memberzugriff).Instance constructors, destructors, and static constructors are not inherited, but all other members are, regardless of their declared accessibility (Member access). Allerdings können je nach ihrem deklarierten Zugriff geerbte Member in einer abgeleiteten Klasse nicht zugreifen.However, depending on their declared accessibility, inherited members might not be accessible in a derived class.
  • Kann eine abgeleitete Klasse ausblenden (ausblenden, die durch Vererbung von) geerbte Member durch neue Member mit demselben Namen bzw. derselben Signatur deklarieren.A derived class can hide (Hiding through inheritance) inherited members by declaring new members with the same name or signature. Beachten Sie jedoch, die durch das Ausblenden eines geerbten Members dieses Element nicht entfernt wird, lediglich erleichtert diesen Member nicht direkt über der abgeleiteten Klasse zugegriffen werden.Note however that hiding an inherited member does not remove that member—it merely makes that member inaccessible directly through the derived class.
  • Eine Instanz einer Klasse enthält einen Satz von alle Instanzenfelder in der Klasse und ihre Basisklassen und eine implizite Konvertierung deklariert (implizite Verweis-) von einem abgeleiteten Typ vorhanden ist, um eine der zugehörigen Basisklassentyp konvertiert.An instance of a class contains a set of all instance fields declared in the class and its base classes, and an implicit conversion (Implicit reference conversions) exists from a derived class type to any of its base class types. Daher kann ein Verweis auf eine Instanz einer abgeleiteten Klasse als Verweis auf eine Instanz einer seiner Basisklassen behandelt werden.Thus, a reference to an instance of some derived class can be treated as a reference to an instance of any of its base classes.
  • Eine Klasse kann virtuelle Methoden, Eigenschaften und Indexer deklarieren, und abgeleitete Klassen können die Implementierung dieser Funktion Member überschreiben.A class can declare virtual methods, properties, and indexers, and derived classes can override the implementation of these function members. Dies ermöglicht es sich um Klassen, weisen polymorphes Verhalten, bei dem die Aktionen, die durch einen Aufruf der Funktion Mitglied variiert je nach den Laufzeittyp der Instanz über den diese Funktionsmember der Member aufgerufen wird.This enables classes to exhibit polymorphic behavior wherein the actions performed by a function member invocation varies depending on the run-time type of the instance through which that function member is invoked.

Der geerbte Member eines Typs konstruierten Klasse sind die Member des Typs direkten Basisklasse (Basisklassen), die wird ermittelt, indem Sie die Typargumente für jedes Vorkommen des entsprechenden Typs des konstruierten Typs ersetzen Parameter in der Class_base Spezifikation.The inherited member of a constructed class type are the members of the immediate base class type (Base classes), which is found by substituting the type arguments of the constructed type for each occurrence of the corresponding type parameters in the class_base specification. Diese Elemente werden wiederum durch Ersetzen der für die einzelnen transformiert Type_parameter in der Element-Deklaration wird das entsprechende Type_argument von der Class_base Spezifikation.These members, in turn, are transformed by substituting, for each type_parameter in the member declaration, the corresponding type_argument of the class_base specification.

class B<U>
{
    public U F(long index) {...}
}

class D<T>: B<T[]>
{
    public T G(string s) {...}
}

Im obigen Beispiel den konstruierten Typ D<int> verfügt über einen nicht geerbte Member public int G(string s) abgerufen, indem Sie das Typargument ersetzt int für den Typparameter T.In the above example, the constructed type D<int> has a non-inherited member public int G(string s) obtained by substituting the type argument int for the type parameter T. D<int> verfügt auch über einen geerbten Member aus der Klassendeklaration B.D<int> also has an inherited member from the class declaration B. Diese geerbte Member wird bestimmt, indem er zuerst ermittelt den Basisklassentyp B<int[]> von D<int> ersetzen int für T in der Basisklasse-Spezifikation B<T[]>.This inherited member is determined by first determining the base class type B<int[]> of D<int> by substituting int for T in the base class specification B<T[]>. Klicken Sie dann als Typargument für B, int[] durch ersetzt, U in public U F(long index), stellt des geerbten Members public int[] F(long index).Then, as a type argument to B, int[] is substituted for U in public U F(long index), yielding the inherited member public int[] F(long index).

Das new-ModifiziererThe new modifier

Ein Class_member_declaration ist zulässig, einen Member mit demselben Namen bzw. derselben Signatur als einen geerbten Member deklarieren.A class_member_declaration is permitted to declare a member with the same name or signature as an inherited member. In diesem Fall Members der abgeleiteten Klasse gilt als ausblenden Member der Basisklasse.When this occurs, the derived class member is said to hide the base class member. Durch das Ausblenden eines geerbten Members ist kein Fehler betrachtet, aber es führt dazu, dass des Compilers eine Warnung ausgegeben.Hiding an inherited member is not considered an error, but it does cause the compiler to issue a warning. Um die Warnung zu unterdrücken, zählen die Deklaration des Members der abgeleiteten Klasse eine new Modifizierer, um anzugeben, dass der abgeleitete Member die Member den Basisklassen ausblenden vorgesehen ist.To suppress the warning, the declaration of the derived class member can include a new modifier to indicate that the derived member is intended to hide the base member. In diesem Thema wird erläutert. im weiteren ausblenden, die durch Vererbung von.This topic is discussed further in Hiding through inheritance.

Wenn eine new Modifizierer in einer Deklaration, der einen geerbten Member auszublenden, nicht enthalten ist, eine Warnung zu diesem Zweck wird ausgegeben.If a new modifier is included in a declaration that doesn't hide an inherited member, a warning to that effect is issued. Diese Warnung unterdrückt wird, durch das Entfernen der new Modifizierer.This warning is suppressed by removing the new modifier.

ZugriffsmodifiziererAccess modifiers

Ein Class_member_declaration haben eines der fünf Arten von deklarierte Zugriffsart (deklariert Barrierefreiheit): public, protected internal, protected, internal , oder private.A class_member_declaration can have any one of the five possible kinds of declared accessibility (Declared accessibility): public, protected internal, protected, internal, or private. Mit Ausnahme der protected internal Kombination, es ist ein Fehler während der Kompilierung mehr als eine Zugriffsmodifizierer angeben.Except for the protected internal combination, it is a compile-time error to specify more than one access modifier. Wenn eine Class_member_declaration enthält keinen Zugriffsmodifizierer, private wird angenommen.When a class_member_declaration does not include any access modifiers, private is assumed.

Enthaltenen TypenConstituent types

Typen, die in der Deklaration eines Elements verwendet werden, sind die einzelnen Typen von diesen Member aufgerufen.Types that are used in the declaration of a member are called the constituent types of that member. Mögliche enthaltenen Typen werden der Typ, der eine Konstante, Feld, Eigenschaft, Ereignis oder des Indexers, der Rückgabetyp einer Methode oder einen Operator und die Parametertypen einer Methode, Indexer, Operator oder Instanzenkonstruktor.Possible constituent types are the type of a constant, field, property, event, or indexer, the return type of a method or operator, and the parameter types of a method, indexer, operator, or instance constructor. Die einzelnen Typen eines Elements müssen mindestens dieselben zugriffsmöglichkeiten bieten wie dieser Member selbst sein (Barrierefreiheit Einschränkungen).The constituent types of a member must be at least as accessible as that member itself (Accessibility constraints).

Statische und MitgliederStatic and instance members

Member einer Klasse sind entweder statische Member oder Instanzmember.Members of a class are either static members or instance members. Im Allgemeinen ist es nützlich, um statische Member als Klassentypen und Instanzmember als von Objekten (Instanzen von Klassentypen) gehören vorstellen.Generally speaking, it is useful to think of static members as belonging to class types and instance members as belonging to objects (instances of class types).

Wenn eine Deklaration Feld, Methode, Eigenschaft, Ereignis, Operator oder Konstruktor enthält einen static Modifizierer verwenden, wird einen statischen Member deklariert.When a field, method, property, event, operator, or constructor declaration includes a static modifier, it declares a static member. Darüber hinaus deklariert die Deklaration einer Konstante oder der Typ implizit einen statischen Member.In addition, a constant or type declaration implicitly declares a static member. Statische Member weisen folgende Merkmale auf:Static members have the following characteristics:

  • Wenn ein statischer Member M verwiesen wird, einem Member_access (Memberzugriff) des Formulars E.M, E müssen kennzeichnen ein Typ mit M.When a static member M is referenced in a member_access (Member access) of the form E.M, E must denote a type containing M. Es ist ein Fehler während der Kompilierung für E um eine Instanz zu kennzeichnen.It is a compile-time error for E to denote an instance.
  • Ein statisches Feld identifiziert genau einen Speicherort für alle Instanzen des angegebenen Klassentyps geschlossene freigegeben werden.A static field identifies exactly one storage location to be shared by all instances of a given closed class type. Unabhängig davon, wie viele Instanzen eines bestimmten geschlossene Klassentyps erstellt werden müssen Sie immer nur eine Kopie eines statischen Felds vorhanden ist.No matter how many instances of a given closed class type are created, there is only ever one copy of a static field.
  • Ein statischer Funktionsmember (Methode, Eigenschaft, Ereignis, Operator oder Konstruktor) kann nicht in einer bestimmten Instanz ausgeführt werden, und es ist ein Fehler während der Kompilierung zum Verweisen auf this in diese ein Funktionsmember.A static function member (method, property, event, operator, or constructor) does not operate on a specific instance, and it is a compile-time error to refer to this in such a function member.

Wenn eine Feld, Methode, Eigenschaft, Ereignis, Indexer, Konstruktor oder Destruktor Deklaration enthält keine static Modifizierer verwenden, wird einen Instanzmember deklariert.When a field, method, property, event, indexer, constructor, or destructor declaration does not include a static modifier, it declares an instance member. (Ein Instanzmember ist einen nicht statisches Member bezeichnet.) Instanzmember weisen folgende Merkmale auf:(An instance member is sometimes called a non-static member.) Instance members have the following characteristics:

  • Wenn ein Instanzmember M verwiesen wird, eine Member_access (Memberzugriff) des Formulars E.M, E muss eine Instanz eines Typs mit deutenM.When an instance member M is referenced in a member_access (Member access) of the form E.M, E must denote an instance of a type containing M. Es ist ein Fehler während der Bindung für E um einen Typ anzugeben.It is a binding-time error for E to denote a type.
  • Jede Instanz einer Klasse enthält einen separaten Satz aller Instanzfelder der Klasse.Every instance of a class contains a separate set of all instance fields of the class.
  • Ein Instanzmember-Funktion (Methode, Eigenschaft, Indexer, Instance-Konstruktor oder Destruktor), die für eine bestimmte Instanz der Klasse ausgeführt wird, und diese Instanz zugegriffen werden kann, als this (diesen Zugriff).An instance function member (method, property, indexer, instance constructor, or destructor) operates on a given instance of the class, and this instance can be accessed as this (This access).

Das folgende Beispiel veranschaulicht die Regeln für den Zugriff auf statische und Instanzmember:The following example illustrates the rules for accessing static and instance members:

class Test
{
    int x;
    static int y;

    void F() {
        x = 1;            // Ok, same as this.x = 1
        y = 1;            // Ok, same as Test.y = 1
    }

    static void G() {
        x = 1;            // Error, cannot access this.x
        y = 1;            // Ok, same as Test.y = 1
    }

    static void Main() {
        Test t = new Test();
        t.x = 1;          // Ok
        t.y = 1;          // Error, cannot access static member through instance
        Test.x = 1;       // Error, cannot access instance member through type
        Test.y = 1;       // Ok
    }
}

Die F Methode zeigt, dass in der Funktion einen Instanzmember einer Simple_name (einfache Namen) Zugriff auf Instanzmember und statische Member verwendet werden können.The F method shows that in an instance function member, a simple_name (Simple names) can be used to access both instance members and static members. Die G Methode zeigt, in einem statischen Funktionsmember, ein Fehler während der Kompilierung einen Instanzmember über den Zugriff auf eine Simple_name.The G method shows that in a static function member, it is a compile-time error to access an instance member through a simple_name. Die Main wird verdeutlicht, dass in einem Member_access (Memberzugriff) Instanzmember über Instanzen zugegriffen werden müssen und statische Member über Typen zugegriffen werden müssen.The Main method shows that in a member_access (Member access), instance members must be accessed through instances, and static members must be accessed through types.

Geschachtelte TypenNested types

Ein Typ, in die Deklaration einer Klasse oder Struktur deklariert wird aufgerufen, eine geschachtelter Typ.A type declared within a class or struct declaration is called a nested type. Ein Typ, der innerhalb einer Kompilierungseinheit oder dem Namespace deklariert wird aufgerufen, wird eine nicht geschachtelten Typ.A type that is declared within a compilation unit or namespace is called a non-nested type.

Im BeispielIn the example

using System;

class A
{
    class B
    {
        static void F() {
            Console.WriteLine("A.B.F");
        }
    }
}

Klasse B ein geschachtelter Typ ist, da es in der Klasse deklariert ist A, und die Klasse A ein nicht geschachtelter Typ ist, da er innerhalb einer Kompilierungseinheit deklariert ist.class B is a nested type because it is declared within class A, and class A is a non-nested type because it is declared within a compilation unit.

Vollqualifizierte NamenFully qualified name

Der vollqualifizierte Name (vollständig qualifizierten Namen) für ein geschachtelter Typ ist S.N , in denen S ist der vollqualifizierte Name des Typs in der N deklariert wird.The fully qualified name (Fully qualified names) for a nested type is S.N where S is the fully qualified name of the type in which type N is declared.

Deklarierter ZugriffDeclared accessibility

Nicht geschachtelten Typen haben public oder internal deklariert Barrierefreiheit und internal Barrierefreiheit werden standardmäßig deklariert.Non-nested types can have public or internal declared accessibility and have internal declared accessibility by default. Geschachtelte Typen haben diese Formen des deklarierte Zugriffsart, sowie eine oder mehrere weitere Formen der deklarierte Zugriffsart, je nachdem, ob der enthaltende Typ eine Klasse oder Struktur:Nested types can have these forms of declared accessibility too, plus one or more additional forms of declared accessibility, depending on whether the containing type is a class or struct:

  • Ein geschachtelter Typ, der in einer Klasse deklariert ist, kann jeden der fünf Arten von deklarierte Zugriffsart aufweisen (public, protected internal, protected, internal, oder private), und wie andere Klassenmember standardmäßig private deklariert Barrierefreiheit.A nested type that is declared in a class can have any of five forms of declared accessibility (public, protected internal, protected, internal, or private) and, like other class members, defaults to private declared accessibility.
  • Ein geschachtelter Typ, der in einer Struktur deklariert ist, kann jeden der deklarierte Zugriffsart in drei Formen aufweisen (public, internal, oder private), und wie andere Strukturmember standardmäßig private Barrierefreiheit deklariert.A nested type that is declared in a struct can have any of three forms of declared accessibility (public, internal, or private) and, like other struct members, defaults to private declared accessibility.

Im BeispielThe example

public class List
{
    // Private data structure
    private class Node
    { 
        public object Data;
        public Node Next;

        public Node(object data, Node next) {
            this.Data = data;
            this.Next = next;
        }
    }

    private Node first = null;
    private Node last = null;

    // Public interface
    public void AddToFront(object o) {...}
    public void AddToBack(object o) {...}
    public object RemoveFromFront() {...}
    public object RemoveFromBack() {...}
    public int Count { get {...} }
}

deklariert eine private geschachtelte Klasse Node.declares a private nested class Node.

Durch das AusblendenHiding

Ein geschachtelter Typ kann ausblenden (Ausblenden von Namen) ein Member der Basisklasse.A nested type may hide (Name hiding) a base member. Die new Modifizierer ist in Deklarationen von geschachtelten Typen zulässig, sodass ausblenden explizit ausgedrückt werden kann.The new modifier is permitted on nested type declarations so that hiding can be expressed explicitly. Im BeispielThe example

using System;

class Base
{
    public static void M() {
        Console.WriteLine("Base.M");
    }
}

class Derived: Base 
{
    new public class M 
    {
        public static void F() {
            Console.WriteLine("Derived.M.F");
        }
    }
}

class Test 
{
    static void Main() {
        Derived.M.F();
    }
}

Zeigt eine geschachtelte Klasse M , die die Methode blendet M in definierten Base.shows a nested class M that hides the method M defined in Base.

Dieser Zugriffthis access

Ein geschachtelter Typ und seinem enthaltenden Typ haben eine besondere Beziehung in Bezug auf nicht This_access (diesen Zugriff).A nested type and its containing type do not have a special relationship with regard to this_access (This access). Insbesondere this innerhalb eines geschachtelten Typs kann nicht verwendet werden, um auf Instanzmember des enthaltenden Typs verweisen.Specifically, this within a nested type cannot be used to refer to instance members of the containing type. In Fällen, in denen ein geschachtelter Typ Zugriff auf die Instanzmember des enthaltenden Typs benötigt, Zugriff bereitgestellt werden kann, durch die Bereitstellung der this für die Instanz des enthaltenden Typs als Konstruktorargument für den geschachtelten Typ.In cases where a nested type needs access to the instance members of its containing type, access can be provided by providing the this for the instance of the containing type as a constructor argument for the nested type. Im folgenden Beispiel wirdThe following example

using System;

class C
{
    int i = 123;

    public void F() {
        Nested n = new Nested(this);
        n.G();
    }

    public class Nested
    {
        C this_c;

        public Nested(C c) {
            this_c = c;
        }

        public void G() {
            Console.WriteLine(this_c.i);
        }
    }
}

class Test
{
    static void Main() {
        C c = new C();
        c.F();
    }
}

Dieses Verfahren veranschaulicht.shows this technique. Eine Instanz von C erstellt eine Instanz des Nested und übergibt Sie eine eigene this zu NestedKonstruktor, um den Zugriff auf bereitzustellen Cdes Instanzmember.An instance of C creates an instance of Nested and passes its own this to Nested's constructor in order to provide subsequent access to C's instance members.

Zugriff auf private und geschützte Member des enthaltenden TypsAccess to private and protected members of the containing type

Ein geschachtelter Typ hat Zugriff auf alle Elemente, die auf seinem enthaltenden Typ, einschließlich, die Mitglieder des enthaltenden Typs zugegriffen werden private und protected Barrierefreiheit deklariert.A nested type has access to all of the members that are accessible to its containing type, including members of the containing type that have private and protected declared accessibility. Im BeispielThe example

using System;

class C 
{
    private static void F() {
        Console.WriteLine("C.F");
    }

    public class Nested 
    {
        public static void G() {
            F();
        }
    }
}

class Test 
{
    static void Main() {
        C.Nested.G();
    }
}

Zeigt eine Klasse C , enthält eine geschachtelte Klasse Nested.shows a class C that contains a nested class Nested. In Nested, die Methode G Ruft die statische Methode F in definierten C, und F wurde deklariert privaten Zugriff.Within Nested, the method G calls the static method F defined in C, and F has private declared accessibility.

Ein geschachtelter Typ kann auch geschützte Member, die in einem Basistyp des enthaltenden Typs definiert zugreifen.A nested type also may access protected members defined in a base type of its containing type. Im BeispielIn the example

using System;

class Base 
{
    protected void F() {
        Console.WriteLine("Base.F");
    }
}

class Derived: Base 
{
    public class Nested 
    {
        public void G() {
            Derived d = new Derived();
            d.F();        // ok
        }
    }
}

class Test 
{
    static void Main() {
        Derived.Nested n = new Derived.Nested();
        n.G();
    }
}

die geschachtelte Klasse Derived.Nested greift auf die geschützte Methode F in definierten DerivedBasisklasse, Base, von Aufrufen durch eine Instanz der Derived.the nested class Derived.Nested accesses the protected method F defined in Derived's base class, Base, by calling through an instance of Derived.

Geschachtelte Typen in generische KlassenNested types in generic classes

Deklaration einer generischen Klasse kann über geschachtelte Typdeklarationen enthalten.A generic class declaration can contain nested type declarations. Die Typparameter der einschließenden Klasse können innerhalb der geschachtelten Typen verwendet werden.The type parameters of the enclosing class can be used within the nested types. Eine geschachtelten Typdeklaration kann weitere Typparameter enthalten, die nur für den geschachtelten Typ gelten.A nested type declaration can contain additional type parameters that apply only to the nested type.

Jede Typdeklaration, die innerhalb der Deklaration einer generischen Klasse ist implizit die Deklaration eines generischen Typs.Every type declaration contained within a generic class declaration is implicitly a generic type declaration. Schreiben einen Verweis auf einen Typ in einem generischen Typ geschachtelt werden, muss mit konstruierten Typs, einschließlich seiner Typargumente benannt werden.When writing a reference to a type nested within a generic type, the containing constructed type, including its type arguments, must be named. Allerdings kann von innerhalb der äußeren Klasse der geschachtelte Typ ohne Qualifikation verwendet werden; der Instanztyp der äußeren Klasse kann implizit verwendet werden, beim Erstellen des geschachtelten Typs.However, from within the outer class, the nested type can be used without qualification; the instance type of the outer class can be implicitly used when constructing the nested type. Das folgende Beispiel zeigt drei richtige Möglichkeiten zum Verweisen auf einen konstruierten Typ aus erstellt Inner; die ersten beiden sind gleichwertig:The following example shows three different correct ways to refer to a constructed type created from Inner; the first two are equivalent:

class Outer<T>
{
    class Inner<U>
    {
        public static void F(T t, U u) {...}
    }

    static void F(T t) {
        Outer<T>.Inner<string>.F(t, "abc");      // These two statements have
        Inner<string>.F(t, "abc");               // the same effect

        Outer<int>.Inner<string>.F(3, "abc");    // This type is different

        Outer.Inner<string>.F(t, "abc");         // Error, Outer needs type arg
    }
}

Obwohl das Gegenteil kann Mitglied Programmierstil, ein Typparameter in einem geschachtelten Typ oder ausblenden Typparameter des äußeren Typs deklariert:Although it is bad programming style, a type parameter in a nested type can hide a member or type parameter declared in the outer type:

class Outer<T>
{
    class Inner<T>        // Valid, hides Outer's T
    {
        public T t;       // Refers to Inner's T
    }
}

Reservierte NamenReserved member names

Um die zugrunde liegenden C#-Laufzeit-Implementierung für jede Quelle-Memberdeklaration zu ermöglichen, die eine Eigenschaft, Ereignis oder Indexer muss die Implementierung zwei Methodensignaturen, die je nach der Art der Memberdeklaration, den Namen und den Typ reservieren.To facilitate the underlying C# run-time implementation, for each source member declaration that is a property, event, or indexer, the implementation must reserve two method signatures based on the kind of the member declaration, its name, and its type. Es ist ein Fehler während der Kompilierung für ein Programm, auch wenn die zugrunde liegende Implementierung für die Laufzeit keine vornimmt deklariert ein Element, dessen Signatur, eines der folgenden übereinstimmt, reservierten Signaturen, verwenden Sie diese Reservierungen.It is a compile-time error for a program to declare a member whose signature matches one of these reserved signatures, even if the underlying run-time implementation does not make use of these reservations.

Die reservierten Namen keine Deklarationen einführen, daher beim Nachschlagen von Membern nicht beteiligt.The reserved names do not introduce declarations, thus they do not participate in member lookup. Eine Deklaration zugeordneten jedoch reservierte Methode Signaturen bei der Vererbung teilnehmen (Vererbung), und können ausgeblendet werden, mit der new Modifizierer (der new-Modifizierer).However, a declaration's associated reserved method signatures do participate in inheritance (Inheritance), and can be hidden with the new modifier (The new modifier).

Die Reservierung dieser Namen erfüllt drei Zwecke:The reservation of these names serves three purposes:

  • Um die zugrunde liegende Implementierung einen normalen Bezeichner als Methodenname für Get verwenden, oder legen Sie den Zugriff auf die C#-Sprachfunktion zu ermöglichen.To allow the underlying implementation to use an ordinary identifier as a method name for get or set access to the C# language feature.
  • Um andere Sprachen zusammenarbeiten, verwenden einen normalen Bezeichner als Methodenname für Get oder legen Sie den Zugriff auf die C#-Sprachfunktion zu ermöglichen.To allow other languages to interoperate using an ordinary identifier as a method name for get or set access to the C# language feature.
  • Um sicherzustellen, dass die Quelle von einem konformen Compiler akzeptiert werden durch einen anderen, akzeptiert, dazu die Einzelheiten der reservierten Member Namen konsistent über alle C#-Implementierungen.To help ensure that the source accepted by one conforming compiler is accepted by another, by making the specifics of reserved member names consistent across all C# implementations.

Die Deklaration eines Destruktors (Destruktoren) bewirkt auch, dass eine Signatur reserviert werden sollen (für Destruktoren Membernamen).The declaration of a destructor (Destructors) also causes a signature to be reserved (Member names reserved for destructors).

Elementnamen, die für Eigenschaften reserviertMember names reserved for properties

Für eine Eigenschaft P (Eigenschaften) vom Typ T, die folgenden Signaturen sind reserviert:For a property P (Properties) of type T, the following signatures are reserved:

T get_P();
void set_P(T value);

Beide Signaturen sind reserviert, auch wenn die Eigenschaft schreibgeschützt oder lesegeschützt ist.Both signatures are reserved, even if the property is read-only or write-only.

Im BeispielIn the example

using System;

class A
{
    public int P {
        get { return 123; }
    }
}

class B: A
{
    new public int get_P() {
        return 456;
    }

    new public void set_P(int value) {
    }
}

class Test
{
    static void Main() {
        B b = new B();
        A a = b;
        Console.WriteLine(a.P);
        Console.WriteLine(b.P);
        Console.WriteLine(b.get_P());
    }
}

eine Klasse A definiert eine schreibgeschützte Eigenschaft P, also Reservieren von Signaturen für get_P und set_P Methoden.a class A defines a read-only property P, thus reserving signatures for get_P and set_P methods. Eine Klasse B leitet sich von A und blendet Sie aus dieser reservierte Signaturen.A class B derives from A and hides both of these reserved signatures. Das Beispiel erzeugt die Ausgabe:The example produces the output:

123
123
456

Elementnamen, die für Ereignisse reserviertMember names reserved for events

Für ein Ereignis E (Ereignisse) eines Delegattyps T, die folgenden Signaturen sind reserviert:For an event E (Events) of delegate type T, the following signatures are reserved:

void add_E(T handler);
void remove_E(T handler);

Für Indexer reservierte ElementnamenMember names reserved for indexers

Für einen Indexer (Indexer) vom Typ T mit Parameter-List L, die folgenden Signaturen sind reserviert:For an indexer (Indexers) of type T with parameter-list L, the following signatures are reserved:

T get_Item(L);
void set_Item(L, T value);

Beide Signaturen sind reserviert, selbst wenn der Indexer schreibgeschützt oder lesegeschützt ist.Both signatures are reserved, even if the indexer is read-only or write-only.

Außerdem den Namen des Members Item ist reserviert.Furthermore the member name Item is reserved.

Elementnamen, die für Destruktoren reserviertMember names reserved for destructors

Für eine Klasse, die einen Destruktor enthält (Destruktoren), die folgende Signatur ist reserviert:For a class containing a destructor (Destructors), the following signature is reserved:

void Finalize();

KonstantenConstants

Ein Konstanten ist ein Klassenmember, der einen konstanten Wert darstellt: ein Wert, der zur Kompilierungszeit berechnet werden kann.A constant is a class member that represents a constant value: a value that can be computed at compile-time. Ein Constant_declaration führt eine oder mehrere Konstanten eines bestimmten Typs.A constant_declaration introduces one or more constants of a given type.

constant_declaration
    : attributes? constant_modifier* 'const' type constant_declarators ';'
    ;

constant_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    ;

constant_declarators
    : constant_declarator (',' constant_declarator)*
    ;

constant_declarator
    : identifier '=' constant_expression
    ;

Ein Constant_declaration eventuell einen Satz von Attribute (Attribute), ein new Modifizierer (der new-Modifizierer), und eine gültige Kombination der vier Zugriffsmodifizierer (Zugriffsmodifizierer).A constant_declaration may include a set of attributes (Attributes), a new modifier (The new modifier), and a valid combination of the four access modifiers (Access modifiers). Die Attribute und Modifizierer, gelten für alle Member deklariert, indem die Constant_declaration.The attributes and modifiers apply to all of the members declared by the constant_declaration. Obwohl Konstanten statische Member, gelten eine Constant_declaration erfordert und keine ermöglicht eine static Modifizierer.Even though constants are considered static members, a constant_declaration neither requires nor allows a static modifier. Es ist ein Fehler für den gleichen Modifizierer für mehrere Male in einer Konstantendeklaration angezeigt werden.It is an error for the same modifier to appear multiple times in a constant declaration.

Die Typ von einem Constant_declaration gibt den Typ der Elemente, die durch die Deklaration eingeführt.The type of a constant_declaration specifies the type of the members introduced by the declaration. Der Typ folgt eine Liste der Constant_declarators, von denen jede einen neuen Member führt.The type is followed by a list of constant_declarators, each of which introduces a new member. Ein Constant_declarator besteht aus einer Bezeichner mit dem das Element, gefolgt vom Namen einer "=" token, gefolgt von einer Constant_expression ( Konstante Ausdrücke), die den Wert des Elements bietet.A constant_declarator consists of an identifier that names the member, followed by an "=" token, followed by a constant_expression (Constant expressions) that gives the value of the member.

Die Typ in eine Konstante angegeben Deklaration muss sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, Enum_type, oder ein Reference_type.The type specified in a constant declaration must be sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, an enum_type, or a reference_type. Jede Constant_expression muss einen Wert des Zieltyps oder eines Typs, der in den Zieltyp konvertiert werden kann, indem eine implizite Konvertierung werden liefern (implizite Konvertierungen).Each constant_expression must yield a value of the target type or of a type that can be converted to the target type by an implicit conversion (Implicit conversions).

Die Typ einer Konstante muss mindestens dieselben zugriffsmöglichkeiten bieten wie die Konstante selbst (Barrierefreiheit Einschränkungen).The type of a constant must be at least as accessible as the constant itself (Accessibility constraints).

Der Wert einer Konstante wird ermittelt, in ein Ausdruck mit einem Simple_name (einfache Namen) oder ein Member_access (Memberzugriff).The value of a constant is obtained in an expression using a simple_name (Simple names) or a member_access (Member access).

Eine Konstante selbst teilnehmen kann eine Constant_expression.A constant can itself participate in a constant_expression. Daher kann eine Konstante verwendet werden, in einem beliebigen Konstrukt, das erfordert eine Constant_expression.Thus, a constant may be used in any construct that requires a constant_expression. Beispiele für solche Konstrukte case Bezeichnungen goto case Anweisungen enum Memberdeklarationen, Attribute und andere Konstanten Deklarationen.Examples of such constructs include case labels, goto case statements, enum member declarations, attributes, and other constant declarations.

Siehe Konstante Ausdrücke, Constant_expression ist ein Ausdruck, der zum Zeitpunkt der Kompilierung vollständig ausgewertet werden kann.As described in Constant expressions, a constant_expression is an expression that can be fully evaluated at compile-time. Da die einzige Möglichkeit zum Erstellen eines nicht-Null-Wert, der eine Reference_type außer string angewendet werden soll die new -Operator, und da die new Operator ist nicht zulässig, eine Constant_ Ausdruck, der einzig mögliche Wert für Konstanten von Reference_types außer string ist null.Since the only way to create a non-null value of a reference_type other than string is to apply the new operator, and since the new operator is not permitted in a constant_expression, the only possible value for constants of reference_types other than string is null.

Wenn ein symbolische Namen für einen konstanten Wert gewünscht ist, aber wenn der Typ des Werts in einer Konstantendeklaration nicht zulässig ist oder wenn der Wert nicht zum Zeitpunkt der Kompilierung von berechnet werden kann eine Constant_expression, readonly (Feld Schreibgeschützte Felder) kann stattdessen verwendet werden.When a symbolic name for a constant value is desired, but when the type of that value is not permitted in a constant declaration, or when the value cannot be computed at compile-time by a constant_expression, a readonly field (Readonly fields) may be used instead.

Deklaration eine Konstante, die mehrere Konstanten deklariert entspricht mehreren Deklarationen der einzelnen Konstanten, mit der gleichen Attribute, Modifizierer, und geben.A constant declaration that declares multiple constants is equivalent to multiple declarations of single constants with the same attributes, modifiers, and type. Beispiel:For example

class A
{
    public const double X = 1.0, Y = 2.0, Z = 3.0;
}

für die folgende Syntax:is equivalent to

class A
{
    public const double X = 1.0;
    public const double Y = 2.0;
    public const double Z = 3.0;
}

Konstanten sind andere Konstanten innerhalb desselben Programms abhängig ist, solange die Abhängigkeiten keine zirkuläre Natur sind zulässig.Constants are permitted to depend on other constants within the same program as long as the dependencies are not of a circular nature. Der Compiler ordnet automatisch die Konstanten Deklarationen in der richtigen Reihenfolge ausgewertet.The compiler automatically arranges to evaluate the constant declarations in the appropriate order. Im BeispielIn the example

class A
{
    public const int X = B.Z + 1;
    public const int Y = 10;
}

class B
{
    public const int Z = A.Y + 1;
}

der Compiler wertet zunächst A.Y, wertet dann B.Z, und schließlich wertet A.X, die Werte erzeugen 10, 11, und 12.the compiler first evaluates A.Y, then evaluates B.Z, and finally evaluates A.X, producing the values 10, 11, and 12. Konstante Deklarationen können auf Konstanten aus anderen Programmen abhängig sind, aber solche Abhängigkeiten sind nur in einer Richtung möglich.Constant declarations may depend on constants from other programs, but such dependencies are only possible in one direction. Im obigen Beispiel auf, wenn A und B deklariert wurden in verschiedenen Programmen, es wäre möglich, dass A.X hängt von B.Z, aber B.Z können nicht gleichzeitig klicken Sie dann abhängig A.Y.Referring to the example above, if A and B were declared in separate programs, it would be possible for A.X to depend on B.Z, but B.Z could then not simultaneously depend on A.Y.

FelderFields

Ein Feld ist ein Member, der eine Variable zugeordnet, ein Objekt oder eine Klasse darstellt.A field is a member that represents a variable associated with an object or class. Ein Field_declaration führt eine oder mehrere Felder eines angegebenen Typs.A field_declaration introduces one or more fields of a given type.

field_declaration
    : attributes? field_modifier* type variable_declarators ';'
    ;

field_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'readonly'
    | 'volatile'
    | field_modifier_unsafe
    ;

variable_declarators
    : variable_declarator (',' variable_declarator)*
    ;

variable_declarator
    : identifier ('=' variable_initializer)?
    ;

variable_initializer
    : expression
    | array_initializer
    ;

Ein Field_declaration eventuell einen Satz von Attribute (Attribute), ein new Modifizierer (der new-Modifizierer), gültige Kombination der vier Zugriffsmodifizierer (Zugriffsmodifizierer), und ein static Modifizierer (statische Felder und Instanzfelder).A field_declaration may include a set of attributes (Attributes), a new modifier (The new modifier), a valid combination of the four access modifiers (Access modifiers), and a static modifier (Static and instance fields). Darüber hinaus eine Field_declaration eventuell eine readonly Modifizierer (schreibgeschützte Felder) oder ein volatile Modifizierer (flüchtige Felder) jedoch nicht beides.In addition, a field_declaration may include a readonly modifier (Readonly fields) or a volatile modifier (Volatile fields) but not both. Die Attribute und Modifizierer, gelten für alle Member deklariert, indem die Field_declaration.The attributes and modifiers apply to all of the members declared by the field_declaration. Es ist ein Fehler für den gleichen Modifizierer für mehrere Male in einer Felddeklaration angezeigt werden.It is an error for the same modifier to appear multiple times in a field declaration.

Die Typ von einem Field_declaration gibt den Typ der Elemente, die durch die Deklaration eingeführt.The type of a field_declaration specifies the type of the members introduced by the declaration. Der Typ folgt eine Liste der Variable_declarators, von denen jede einen neuen Member führt.The type is followed by a list of variable_declarators, each of which introduces a new member. Ein Variable_declarator besteht aus einer Bezeichner mit dem Namen dieses Members, optional gefolgt von einer "=" token und einem Variable_initializer ( Variableninitialisierern), die ermöglicht, dass des Anfangswert dieses Members.A variable_declarator consists of an identifier that names that member, optionally followed by an "=" token and a variable_initializer (Variable initializers) that gives the initial value of that member.

Die Typ eines Felds muss mindestens dieselben zugriffsmöglichkeiten bieten wie das Feld selbst (Barrierefreiheit Einschränkungen).The type of a field must be at least as accessible as the field itself (Accessibility constraints).

Der Wert eines Felds wird ermittelt, in einem Ausdruck mit einer Simple_name (einfache Namen) oder ein Member_access (Memberzugriff).The value of a field is obtained in an expression using a simple_name (Simple names) or a member_access (Member access). Der Wert eines Felds nicht schreibgeschützte geändert wird, mithilfe einer Zuweisung (Zuweisungsoperatoren).The value of a non-readonly field is modified using an assignment (Assignment operators). Der Wert eines Felds nicht schreibgeschützte kann sein, abgerufen und das Bearbeiten mit postfix-Inkrement und Dekrement-Operatoren (Postfix-Inkrement und Dekrement-Operatoren) und Präfix-Inkrement und Dekrement-Operatoren (Präfix Inkrement-und Dekrementoperatoren).The value of a non-readonly field can be both obtained and modified using postfix increment and decrement operators (Postfix increment and decrement operators) and prefix increment and decrement operators (Prefix increment and decrement operators).

Eine Felddeklaration, die mehrere Felder deklariert entspricht mehreren Deklarationen der einzelnen Felder mit der gleichen Attribute, Modifizierer, und geben.A field declaration that declares multiple fields is equivalent to multiple declarations of single fields with the same attributes, modifiers, and type. Beispiel:For example

class A
{
    public static int X = 1, Y, Z = 100;
}

für die folgende Syntax:is equivalent to

class A
{
    public static int X = 1;
    public static int Y;
    public static int Z = 100;
}

Statische und FelderStatic and instance fields

Wenn eine Felddeklaration enthält eine static Modifizierer, die Felder, die durch die Deklaration eingeführt sind statische Felder.When a field declaration includes a static modifier, the fields introduced by the declaration are static fields. Wenn kein static Modifizierer vorhanden ist, wird die Felder, die durch die Deklaration eingeführt sind Instanzfelder.When no static modifier is present, the fields introduced by the declaration are instance fields. Statische Felder und Instanzfelder sind zwei verschiedene Arten von Variablen (Variablen) von c# unterstützt, und gelegentlich werden sie bezeichnet als statische Variablen und Instanzvariablen bzw.Static fields and instance fields are two of the several kinds of variables (Variables) supported by C#, and at times they are referred to as static variables and instance variables, respectively.

Ein statisches Feld gehört nicht zu einer bestimmten Instanz. Stattdessen es für alle Instanzen eines Typs geschlossene genutzt (offene und geschlossene Typen).A static field is not part of a specific instance; instead, it is shared amongst all instances of a closed type (Open and closed types). Unabhängig davon, wie viele Instanzen eines geschlossenen Klassentyps erstellt werden ist es immer nur eine Kopie eines statischen Felds für die Domäne der zugehörigen Anwendung.No matter how many instances of a closed class type are created, there is only ever one copy of a static field for the associated application domain.

Zum Beispiel:For example:

class C<V>
{
    static int count = 0;

    public C() {
        count++;
    }

    public static int Count {
        get { return count; }
    }
}

class Application
{
    static void Main() {
        C<int> x1 = new C<int>();
        Console.WriteLine(C<int>.Count);        // Prints 1

        C<double> x2 = new C<double>();
        Console.WriteLine(C<int>.Count);        // Prints 1

        C<int> x3 = new C<int>();
        Console.WriteLine(C<int>.Count);        // Prints 2
    }
}

Ein Instanzenfeld gehört zu einer Instanz.An instance field belongs to an instance. Insbesondere enthält jede Instanz einer Klasse einen separaten Satz von aller Instanzfelder dieser Klasse.Specifically, every instance of a class contains a separate set of all the instance fields of that class.

Wenn ein Feld verwiesen wird, einem Member_access (Memberzugriff) des Formulars E.M, wenn M ist ein statisches Feld E müssen kennzeichnen ein Typ mit M , und wenn M ist ein Instanzfeld E muss eine Instanz von einem Typ mit deuten M.When a field is referenced in a member_access (Member access) of the form E.M, if M is a static field, E must denote a type containing M, and if M is an instance field, E must denote an instance of a type containing M.

Die Unterschiede zwischen statischen und Instanzmember finden Sie weiter unten in statische und Instanzmember.The differences between static and instance members are discussed further in Static and instance members.

Schreibgeschützte FelderReadonly fields

Wenn eine Field_declaration enthält eine readonly Modifizierer, die Felder, die durch die Deklaration eingeführt sind schreibgeschützte Felder.When a field_declaration includes a readonly modifier, the fields introduced by the declaration are readonly fields. Direkte Zuweisungen an schreibgeschützte Felder können nur als Teil dieser Deklaration oder in einem Instanzenkonstruktor oder einen statischen Konstruktor in derselben Klasse auftreten.Direct assignments to readonly fields can only occur as part of that declaration or in an instance constructor or static constructor in the same class. (Ein schreibgeschütztes Feld kann mehrere Male in diesen Kontexten zugewiesen werden.) Insbesondere direkten Zuweisungen für eine readonly Feld sind nur in den folgenden Kontexten zulässig:(A readonly field can be assigned to multiple times in these contexts.) Specifically, direct assignments to a readonly field are permitted only in the following contexts:

  • In der Variable_declarator wird das Feld (mit einem Variable_initializer in der Deklaration).In the variable_declarator that introduces the field (by including a variable_initializer in the declaration).
  • Für ein Instanzenfeld in den Instanzkonstruktoren der Klasse, die die Felddeklaration enthält. für ein statisches Feld im statischen Konstruktor der Klasse, die die Felddeklaration enthält.For an instance field, in the instance constructors of the class that contains the field declaration; for a static field, in the static constructor of the class that contains the field declaration. Hierbei handelt es sich auch um die einzigen Fälle, in dem Übergeben einer readonly Feld als ein out oder ref Parameter.These are also the only contexts in which it is valid to pass a readonly field as an out or ref parameter.

Beim Zuweisen einer readonly Feld ein, oder übergeben Sie sie als ein out oder ref Parameter in einem anderen Kontext ist ein Fehler während der Kompilierung.Attempting to assign to a readonly field or pass it as an out or ref parameter in any other context is a compile-time error.

Verwenden für Konstanten statische schreibgeschützte FelderUsing static readonly fields for constants

Ein static readonly Feld ist hilfreich, wenn ein symbolische Namen für einen konstanten Wert gewünscht ist, aber wenn der Typ des Werts in nicht zulässig ist eine const Deklaration, oder wenn der Wert nicht zur Kompilierzeit berechnet werden kann.A static readonly field is useful when a symbolic name for a constant value is desired, but when the type of the value is not permitted in a const declaration, or when the value cannot be computed at compile-time. Im BeispielIn the example

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);

    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

die Black, White, Red, Green, und Blue Member können nicht deklariert werden, als const Member, da ihre Werte nicht zur Kompilierungszeit berechnet werden können.the Black, White, Red, Green, and Blue members cannot be declared as const members because their values cannot be computed at compile-time. Deklarieren Sie sie jedoch static readonly stattdessen nahezu die gleiche Wirkung hat.However, declaring them static readonly instead has much the same effect.

Versionsverwaltung von Konstanten und statische schreibgeschützte FelderVersioning of constants and static readonly fields

Konstanten und schreibgeschützte Felder haben eine unterschiedliche binäre versionsverwaltung-Semantik.Constants and readonly fields have different binary versioning semantics. Wenn eine Konstante in ein Ausdruck verwiesen wird, wird der Wert der Konstanten zur Kompilierzeit abgerufen, aber wenn ein Ausdruck ein schreibgeschütztes Feld verwiesen wird, wird der Wert des Felds nicht bis zur Laufzeit abgerufen.When an expression references a constant, the value of the constant is obtained at compile-time, but when an expression references a readonly field, the value of the field is not obtained until run-time. Betrachten Sie eine Anwendung, die aus zwei verschiedenen Programmen besteht aus:Consider an application that consists of two separate programs:

using System;

namespace Program1
{
    public class Utils
    {
        public static readonly int X = 1;
    }
}

namespace Program2
{
    class Test
    {
        static void Main() {
            Console.WriteLine(Program1.Utils.X);
        }
    }
}

Die Program1 und Program2 Namespaces kennzeichnen die beiden Programme, die separat kompiliert werden.The Program1 and Program2 namespaces denote two programs that are compiled separately. Da Program1.Utils.X ist als ein statisches schreibgeschütztes Feld, die Ausgabe des Werts von deklariert die Console.WriteLine Anweisung zur Kompilierzeit nicht bekannt, aber stattdessen zur Laufzeit abgerufen wird.Because Program1.Utils.X is declared as a static readonly field, the value output by the Console.WriteLine statement is not known at compile-time, but rather is obtained at run-time. Also wenn der Wert des X geändert wird und Program1 erneut kompiliert wird, die Console.WriteLine Anweisung gibt der neue Wert, selbst wenn Program2 ist nicht neu kompiliert.Thus, if the value of X is changed and Program1 is recompiled, the Console.WriteLine statement will output the new value even if Program2 isn't recompiled. Hatte jedoch X wurde eine Konstante, die den Wert der X würde abgerufen haben, wurden zum Zeitpunkt Program2 kompiliert wurde, und würde nicht betroffen von Änderungen in Program1 bis Program2 neu kompiliert wird.However, had X been a constant, the value of X would have been obtained at the time Program2 was compiled, and would remain unaffected by changes in Program1 until Program2 is recompiled.

Flüchtige FelderVolatile fields

Wenn eine Field_declaration enthält eine volatile Modifizierer, die Felder, der durch diese Deklaration sind flüchtige Felder.When a field_declaration includes a volatile modifier, the fields introduced by that declaration are volatile fields.

Für nicht flüchtige Felder Optimierungstechniken, die Anweisungen neu anordnet können zu unerwarteten und unvorhersehbaren Ergebnissen führen in Multithreaded-Programmen, die Zugriff auf Felder ohne Synchronisierung, z. B. über die Lock_statement (Die sperranweisung).For non-volatile fields, optimization techniques that reorder instructions can lead to unexpected and unpredictable results in multi-threaded programs that access fields without synchronization such as that provided by the lock_statement (The lock statement). Diese Optimierungen können durch den Compiler, durch die Laufzeit-System oder von der Hardware ausgeführt werden.These optimizations can be performed by the compiler, by the run-time system, or by hardware. Für flüchtige Felder sind solche Neuanordnen von Optimierungen beschränkt:For volatile fields, such reordering optimizations are restricted:

  • Ein Lesevorgang eines flüchtigen Felds wird aufgerufen, eine Volatile lesen.A read of a volatile field is called a volatile read. Ein flüchtiger Lesevorgang wurde "acquire-Semantik;" Es ist garantiert, also bevor alle Verweise auf den Speicher auftreten, die auftreten, nachdem sie in der anweisungsabfolge.A volatile read has "acquire semantics"; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence.
  • Ein Schreibvorgang eines flüchtigen Felds wird aufgerufen, eine flüchtiger Schreibvorgang.A write of a volatile field is called a volatile write. Ein flüchtiger Schreibvorgang hat "release Semantik"; Es ist garantiert, also nach Verweise Arbeitsspeicher vor der Write-Anweisung in der anweisungsabfolge ausgeführt.A volatile write has "release semantics"; that is, it is guaranteed to happen after any memory references prior to the write instruction in the instruction sequence.

Diese Einschränkungen stellen sicher, dass alle Threads volatile-Schreibvorgänge, die von einem anderen Thread ausgeführt werden, in der Reihenfolge ihrer Ausführung berücksichtigen.These restrictions ensure that all threads will observe volatile writes performed by any other thread in the order in which they were performed. Keine entsprechende Implementierung ist nicht erforderlich, zu der eine einzelne gesamte Sortierung von flüchtigen Schreibvorgänge von allen Threads der Ausführung sehen.A conforming implementation is not required to provide a single total ordering of volatile writes as seen from all threads of execution. Der Typ eines flüchtigen Felds muss es sich um eine der folgenden sein:The type of a volatile field must be one of the following:

  • Ein Reference_type.A reference_type.
  • Der Typ byte, sbyte, short, ushort, int, uint, char, float, bool, System.IntPtr, oder System.UIntPtr.The type byte, sbyte, short, ushort, int, uint, char, float, bool, System.IntPtr, or System.UIntPtr.
  • Ein Enum_type müssen einen Enum-Basistyp des byte, sbyte, short, ushort, int, oder uint.An enum_type having an enum base type of byte, sbyte, short, ushort, int, or uint.

Im BeispielThe example

using System;
using System.Threading;

class Test
{
    public static int result;   
    public static volatile bool finished;

    static void Thread2() {
        result = 143;    
        finished = true; 
    }

    static void Main() {
        finished = false;

        // Run Thread2() in a new thread
        new Thread(new ThreadStart(Thread2)).Start();

        // Wait for Thread2 to signal that it has a result by setting
        // finished to true.
        for (;;) {
            if (finished) {
                Console.WriteLine("result = {0}", result);
                return;
            }
        }
    }
}

erzeugt die Ausgabe:produces the output:

result = 143

In diesem Beispiel ist die Methode Main startet einen neuen Thread, der die Methode ausgeführt wird Thread2.In this example, the method Main starts a new thread that runs the method Thread2. Diese Methode speichert einen Wert in ein nicht flüchtiges Feld namens result, dann speichert true im flüchtigen Felds finished.This method stores a value into a non-volatile field called result, then stores true in the volatile field finished. Der Hauptthread wartet auf das Feld finished festgelegt werden, um true, liest dann das Feld result.The main thread waits for the field finished to be set to true, then reads the field result. Da finished deklariert wurde, volatile, der Haupt-Thread muss den Wert lesen 143 aus dem Feld result.Since finished has been declared volatile, the main thread must read the value 143 from the field result. Wenn das Feld finished nicht deklariert wurde volatile, es wäre für den Store, um zulässige result an den primären Thread nach dem Speichervorgang für sichtbar finished, und somit für den Hauptthread, lesen den Wert 0 aus der Feld result.If the field finished had not been declared volatile, then it would be permissible for the store to result to be visible to the main thread after the store to finished, and hence for the main thread to read the value 0 from the field result. Deklarieren von finished als eine volatile Feld verhindert, dass solche Inkonsistenzen.Declaring finished as a volatile field prevents any such inconsistency.

Feld-InitialisierungField initialization

Der Anfangswert eines Felds, ob es ein statisches Feld oder ein Instanzenfeld, ist der Standardwert (Standardwerte) der Typ des Felds.The initial value of a field, whether it be a static field or an instance field, is the default value (Default values) of the field's type. Es ist nicht möglich, beachten Sie den Wert eines Felds aus, bevor diese standardinitialisierung aufgetreten, und ein Feld daher nie ist "nicht initialisiert".It is not possible to observe the value of a field before this default initialization has occurred, and a field is thus never "uninitialized". Im BeispielThe example

using System;

class Test
{
    static bool b;
    int i;

    static void Main() {
        Test t = new Test();
        Console.WriteLine("b = {0}, i = {1}", b, t.i);
    }
}

erzeugt die Ausgabeproduces the output

b = False, i = 0

Da b und i sind beide automatisch mit Standardwerten initialisiert.because b and i are both automatically initialized to default values.

VariableninitialisierernVariable initializers

Herausgeberkontos ausgewiesenen Form Felddeklarationen Variable_initializers.Field declarations may include variable_initializers. Für statische Felder entsprechen Variableninitialisierern zuweisungsanweisungen, die während der klasseninitialisierung ausgeführt werden.For static fields, variable initializers correspond to assignment statements that are executed during class initialization. Beispielsweise entsprechen Feldern Variableninitialisierern zuweisungsanweisungen, die ausgeführt werden, wenn eine Instanz der Klasse erstellt wird.For instance fields, variable initializers correspond to assignment statements that are executed when an instance of the class is created.

Im BeispielThe example

using System;

class Test
{
    static double x = Math.Sqrt(2.0);
    int i = 100;
    string s = "Hello";

    static void Main() {
        Test a = new Test();
        Console.WriteLine("x = {0}, i = {1}, s = {2}", x, a.i, a.s);
    }
}

erzeugt die Ausgabeproduces the output

x = 1.4142135623731, i = 100, s = Hello

Da eine Zuweisung zu x tritt auf, wenn statischen Feldinitialisierer ausführen und Zuweisungen zu i und s auftreten, wenn die Instanzenfeldinitialisierer ausführen.because an assignment to x occurs when static field initializers execute and assignments to i and s occur when the instance field initializers execute.

Die standardinitialisierung-Wert in beschriebenen Feld Initialisierung tritt für alle Felder einschließlich der Felder, die Variable initialisiert werden.The default value initialization described in Field initialization occurs for all fields, including fields that have variable initializers. Wenn eine Klasse initialisiert wird, daher alle statischen Felder in dieser Klasse werden zuerst auf ihre Standardwerte initialisiert, und klicken Sie dann die statischen Feldinitialisierer in der Reihenfolge im Text ausgeführt werden.Thus, when a class is initialized, all static fields in that class are first initialized to their default values, and then the static field initializers are executed in textual order. Wenn eine Instanz einer Klasse erstellt wird, ebenso alle Instanzenfelder in dieser Instanz werden zuerst auf ihre Standardwerte initialisiert, und klicken Sie dann die Instanzenfeldinitialisierer in der Reihenfolge im Text ausgeführt werden.Likewise, when an instance of a class is created, all instance fields in that instance are first initialized to their default values, and then the instance field initializers are executed in textual order.

Es ist möglich, für statische Felder mit Variableninitialisierern an, die im Standardzustand Wert beachtet werden.It is possible for static fields with variable initializers to be observed in their default value state. Dies ist jedoch dringend davon abgeraten, als eine Frage des Stils.However, this is strongly discouraged as a matter of style. Im BeispielThe example

using System;

class Test
{
    static int a = b + 1;
    static int b = a + 1;

    static void Main() {
        Console.WriteLine("a = {0}, b = {1}", a, b);
    }
}

Dieses Verhalten dargestellt.exhibits this behavior. Trotz der zirkulären Definitionen von einer und b, das Programm ist ungültig.Despite the circular definitions of a and b, the program is valid. Dies führt in der AusgabeIt results in the output

a = 1, b = 2

Da die statischen Felder a und b werden initialisiert, um 0 (der Standardwert für int) vor der Ausführung sind.because the static fields a and b are initialized to 0 (the default value for int) before their initializers are executed. Bei den Initialisierer für a ausgeführt wird, wird den Wert des b ist 0 (null), und daher a wird initialisiert 1.When the initializer for a runs, the value of b is zero, and so a is initialized to 1. Bei den Initialisierer für b ausgeführt wird, wird den Wert des a ist bereits 1, und daher b wird initialisiert 2.When the initializer for b runs, the value of a is already 1, and so b is initialized to 2.

Initialisierung statischer FelderStatic field initialization

Die statische Variable Feldinitialisierer einer Klasse entsprechen einer Sequenz von Zuweisungen, die in der Reihenfolge im Text ausgeführt werden, in denen sie in der Klassendeklaration angezeigt werden.The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration. Wenn ein statischer Konstruktor (statische Konstruktoren) vorhanden ist in der Klasse, von der statischen Feldinitialisierer ausgeführt direkt vor dem Ausführen dieser statischen Konstruktors.If a static constructor (Static constructors) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Andernfalls werden die statischen Feldinitialisierer zu einem Zeitpunkt abhängig von der Implementierung vor der ersten Verwendung eines statischen Felds dieser Klasse ausgeführt.Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class. Im BeispielThe example

using System;

class Test 
{ 
    static void Main() {
        Console.WriteLine("{0} {1}", B.Y, A.X);
    }

    public static int F(string s) {
        Console.WriteLine(s);
        return 1;
    }
}

class A
{
    public static int X = Test.F("Init A");
}

class B
{
    public static int Y = Test.F("Init B");
}

kann entweder die Ausgabe erzeugt:might produce either the output:

Init A
Init B
1 1

oder der Ausgabe:or the output:

Init B
Init A
1 1

Da die Ausführung von XInitialisierer und YInitialisierer konnte in beliebiger Reihenfolge auftreten; diese sind nur eingeschränkt, die auftreten, bevor Sie die Verweise auf diese Felder.because the execution of X's initializer and Y's initializer could occur in either order; they are only constrained to occur before the references to those fields. Aber im Beispiel:However, in the example:

using System;

class Test
{
    static void Main() {
        Console.WriteLine("{0} {1}", B.Y, A.X);
    }

    public static int F(string s) {
        Console.WriteLine(s);
        return 1;
    }
}

class A
{
    static A() {}

    public static int X = Test.F("Init A");
}

class B
{
    static B() {}

    public static int Y = Test.F("Init B");
}

die Ausgabe muss sein:the output must be:

Init B
Init A
1 1

Da die Regeln für die beim Ausführen der statischer Konstruktors (gemäß statische Konstruktoren) bereitstellen, die Bdes statischen Konstruktor (und somit Bdes statischen Feldinitialisierer) müssen ausführen, bevor Ades statischen Konstruktor und Feldinitialisierer.because the rules for when static constructors execute (as defined in Static constructors) provide that B's static constructor (and hence B's static field initializers) must run before A's static constructor and field initializers.

Initialisierung von InstanzfeldernInstance field initialization

Die Variable Instanzenfeld einer Klasse entsprechen einer Sequenz von Zuweisungen, die beim Einstieg in eines der Instanzkonstruktoren sofort ausgeführt werden (Konstruktorinitialisierer) dieser Klasse.The instance field variable initializers of a class correspond to a sequence of assignments that are executed immediately upon entry to any one of the instance constructors (Constructor initializers) of that class. Die Variable Initialisierer werden in der Reihenfolge im Text ausgeführt in denen sie in der Klassendeklaration vorkommen.The variable initializers are executed in the textual order in which they appear in the class declaration. Die Klasse erstellen und initialisieren Prozess ist unter Instanzkonstruktoren.The class instance creation and initialization process is described further in Instance constructors.

Einem Variableninitialisierer für ein Instanzfeld kann nicht zu erstellende Instanz verweisen.A variable initializer for an instance field cannot reference the instance being created. Daher wird ein Kompilierzeitfehler auf this in einem Variableninitialisierer, als es ist ein Fehler während der Kompilierung für eine Variable Initialisierer auf beliebiger Instanzmember über eine Simple_name.Thus, it is a compile-time error to reference this in a variable initializer, as it is a compile-time error for a variable initializer to reference any instance member through a simple_name. Im BeispielIn the example

class A
{
    int x = 1;
    int y = x + 1;        // Error, reference to instance member of this
}

die Variable Initialisierer für y führt zu einem Fehler während der Kompilierung, da sie ein Mitglied der zu erstellenden Instanz verweist.the variable initializer for y results in a compile-time error because it references a member of the instance being created.

MethodenMethods

Eine Methode ist ein Member, das eine Berechnung oder eine Aktion implementiert, die durch ein Objekt oder eine Klasse durchgeführt werden kann.A method is a member that implements a computation or action that can be performed by an object or class. Methoden deklariert werden, mithilfe von Method_declarations:Methods are declared using method_declarations:

method_declaration
    : method_header method_body
    ;

method_header
    : attributes? method_modifier* 'partial'? return_type member_name type_parameter_list?
      '(' formal_parameter_list? ')' type_parameter_constraints_clause*
    ;

method_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | 'async'
    | method_modifier_unsafe
    ;

return_type
    : type
    | 'void'
    ;

member_name
    : identifier
    | interface_type '.' identifier
    ;

method_body
    : block
    | '=>' expression ';'
    | ';'
    ;

Ein Method_declaration eventuell einen Satz von Attribute (Attribute) und eine gültige Kombination der vier Zugriffsmodifizierer (Zugriffsmodifizierer ), wird die new (der new-Modifizierer), static (statische und Instanzmethoden), virtual (virtuelle Methoden), override (Methoden außer Kraft setzen), sealed (Versiegelte Methoden), abstract (abstrakten Methoden), und extern (Externe Methoden) Modifizierer.A method_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), static (Static and instance methods), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

Eine Deklaration verfügt über eine gültige Kombination von Modifizierern aus, wenn alle der folgenden Bedingungen erfüllt sind:A declaration has a valid combination of modifiers if all of the following are true:

  • Die Deklaration enthält eine gültige Kombination von Zugriffsmodifizierer (Zugriffsmodifizierer).The declaration includes a valid combination of access modifiers (Access modifiers).
  • Die Deklaration ist nicht derselben Modifizierer mehrmals enthalten.The declaration does not include the same modifier multiple times.
  • Die Deklaration enthält mindestens eine der folgenden Modifizierer: static, virtual, und override.The declaration includes at most one of the following modifiers: static, virtual, and override.
  • Die Deklaration enthält mindestens eine der folgenden Modifizierer: new und override.The declaration includes at most one of the following modifiers: new and override.
  • Wenn die Deklaration enthält die abstract Modifizierer, und klicken Sie dann auf die Deklaration umfasst keine der folgenden Modifizierer: static, virtual, sealed oder extern.If the declaration includes the abstract modifier, then the declaration does not include any of the following modifiers: static, virtual, sealed or extern.
  • Wenn die Deklaration enthält die private Modifizierer, und klicken Sie dann auf die Deklaration umfasst keine der folgenden Modifizierer: virtual, override, oder abstract.If the declaration includes the private modifier, then the declaration does not include any of the following modifiers: virtual, override, or abstract.
  • Wenn die Deklaration enthält die sealed Modifizierer, und klicken Sie dann auf die Deklaration enthält auch die override Modifizierer.If the declaration includes the sealed modifier, then the declaration also includes the override modifier.
  • Wenn die Deklaration enthält die partial Modifizierer, dann umfasst keine der folgenden Modifizierer: new, public, protected, internal, private, virtual, sealed, override , abstract, oder extern.If the declaration includes the partial modifier, then it does not include any of the following modifiers: new, public, protected, internal, private, virtual, sealed, override, abstract, or extern.

Eine Methode mit dem async -Modifizierer ist eine asynchrone Funktion und die in beschriebenen Regeln folgt asynchrone Funktionen.A method that has the async modifier is an async function and follows the rules described in Async functions.

Die Return_type Deklaration gibt den Typ des Werts berechnet und zurückgegeben wird, von der Methode einer Methode an.The return_type of a method declaration specifies the type of the value computed and returned by the method. Die Return_type ist void , wenn die Methode keinen Wert zurückgibt.The return_type is void if the method does not return a value. Wenn die Deklaration enthält die partial Modifizierer, und klicken Sie dann auf der Rückgabetyp muss void.If the declaration includes the partial modifier, then the return type must be void.

Die Member_name gibt den Namen der Methode.The member_name specifies the name of the method. Wenn die Methode eine explizite Schnittstellenmember-Implementierung ist (explizite Implementierungen eines Schnittstellenmembers), wird die Member_name ist einfach ein Bezeichner.Unless the method is an explicit interface member implementation (Explicit interface member implementations), the member_name is simply an identifier. Für eine explizite Schnittstellenmember-Implementierung die Member_name besteht aus einer Interface_type gefolgt von einem "." und ein Bezeichner.For an explicit interface member implementation, the member_name consists of an interface_type followed by a "." and an identifier.

Der optionale Type_parameter_list gibt an, die Typparameter der Methode (Typparameter).The optional type_parameter_list specifies the type parameters of the method (Type parameters). Wenn eine Type_parameter_list angegeben ist, wird die Methode eine generische Methode.If a type_parameter_list is specified the method is a generic method. Wenn die Methode verfügt über eine extern Modifizierer eine Type_parameter_list kann nicht angegeben werden.If the method has an extern modifier, a type_parameter_list cannot be specified.

Der optionale Formal_parameter_list gibt die Parameter der Methode (Methodenparameter).The optional formal_parameter_list specifies the parameters of the method (Method parameters).

Der optionale Type_parameter_constraints_clauses angeben von Einschränkungen für einzelne Typparameter (Geben Sie die Einschränkungen für Typparameter) und kann nur angegeben werden, wenn eine Type_parameter_ Liste ebenfalls angegeben wird, und die Methode verfügt nicht über eine override Modifizierer.The optional type_parameter_constraints_clauses specify constraints on individual type parameters (Type parameter constraints) and may only be specified if a type_parameter_list is also supplied, and the method does not have an override modifier.

Die Return_type und alle referenzierten Typen der Formal_parameter_list einer Methode muss mindestens dieselben zugriffsmöglichkeiten bieten wie die Methode selbst (Barrierefreiheit Einschränkungen).The return_type and each of the types referenced in the formal_parameter_list of a method must be at least as accessible as the method itself (Accessibility constraints).

Die Method_body ist entweder ein Semikolon, ein Anweisungstext oder ausdruckskörper.The method_body is either a semicolon, a statement body or an expression body. Eine-Anweisungstext besteht aus einem Block, der angibt, dass der Anweisungen ausgeführt werden, wenn die Methode aufgerufen wird.A statement body consists of a block, which specifies the statements to execute when the method is invoked. Ein ausdruckskörper besteht aus => gefolgt von einem Ausdruck und ein Semikolon, und gibt einen einzelnen Ausdruck ausführen, wenn die Methode aufgerufen wird.An expression body consists of => followed by an expression and a semicolon, and denotes a single expression to perform when the method is invoked.

Für abstract und extern Methoden, die Method_body besteht einfach aus einem Semikolon.For abstract and extern methods, the method_body consists simply of a semicolon. Für partial Methoden der Method_body kann entweder ein Semikolon, einem Blocktext oder einen ausdruckskörper bestehen.For partial methods the method_body may consist of either a semicolon, a block body or an expression body. Für alle anderen Methoden die Method_body ist ein Blocktext oder einen ausdruckskörper.For all other methods, the method_body is either a block body or an expression body.

Wenn die Method_body besteht aus einem Semikolon, und klicken Sie dann die Deklaration möglicherweise nicht enthalten. die async Modifizierer.If the method_body consists of a semicolon, then the declaration may not include the async modifier.

Der Name, der Liste der Typparameter und die Liste der formalen Parameter einer Methode definieren, die Signatur (Signaturen und überladen) der Methode.The name, the type parameter list and the formal parameter list of a method define the signature (Signatures and overloading) of the method. Insbesondere besteht aus die Signatur einer Methode den Namen, die Anzahl der Parameter vom Typ und die Anzahl, Modifizierer, und Typen der formalen Parameter.Specifically, the signature of a method consists of its name, the number of type parameters and the number, modifiers, and types of its formal parameters. Für diese Zwecke wird einen Typparameter der Methode, die in den Typ eines formalen Parameters auftritt, nicht mit dem Namen, aber anhand ihrer Ordnungsposition in der Liste der Typargumente der Methode identifiziert. Der Rückgabetyp ist nicht Teil der Signatur einer Methode, noch werden die Namen der Typparameter oder die formalen Parameter.For these purposes, any type parameter of the method that occurs in the type of a formal parameter is identified not by its name, but by its ordinal position in the type argument list of the method.The return type is not part of a method's signature, nor are the names of the type parameters or the formal parameters.

Der Name einer Methode muss die Namen aller anderen nicht--Methoden, in der gleichen Klasse deklariert unterscheiden.The name of a method must differ from the names of all other non-methods declared in the same class. Darüber hinaus die Signatur einer Methode muss von den Signaturen aller anderen in derselben Klasse deklarierten Methoden unterscheiden, und zwei in der gleichen Klasse deklarierte Methoden dürfen keine Signaturen, die ausschließlich vom unterscheiden ref und out.In addition, the signature of a method must differ from the signatures of all other methods declared in the same class, and two methods declared in the same class may not have signatures that differ solely by ref and out.

Der Methode Type_parametersind im Gültigkeitsbereich der Method_declaration, und können verwendet werden, um die von Formulartypen in diesem Bereich in der gesamten Return_type, Method_body, und Type_parameter_constraints_clauses jedoch nicht in Attribute.The method's type_parameters are in scope throughout the method_declaration, and can be used to form types throughout that scope in return_type, method_body, and type_parameter_constraints_clauses but not in attributes.

Alle formalen Parametern und Typparametern müssen unterschiedliche Namen aufweisen.All formal parameters and type parameters must have different names.

MethodenparameterMethod parameters

Die Parameter einer Methode, sofern vorhanden, werden von der Methode deklariert Formal_parameter_list.The parameters of a method, if any, are declared by the method's formal_parameter_list.

formal_parameter_list
    : fixed_parameters
    | fixed_parameters ',' parameter_array
    | parameter_array
    ;

fixed_parameters
    : fixed_parameter (',' fixed_parameter)*
    ;

fixed_parameter
    : attributes? parameter_modifier? type identifier default_argument?
    ;

default_argument
    : '=' expression
    ;

parameter_modifier
    : 'ref'
    | 'out'
    | 'this'
    ;

parameter_array
    : attributes? 'params' array_type identifier
    ;

Liste der formalen Parameter besteht aus einen oder mehrere durch Trennzeichen getrennte Parameter von denen nur die letzte möglicherweise eine Parameter_array.The formal parameter list consists of one or more comma-separated parameters of which only the last may be a parameter_array.

Ein Fixed_parameter besteht aus einer optionalen Gruppe von Attribute (Attribute), ein optionales ref, out oder this Modifizierer ein Typ, Bezeichner und einem optionalen Default_argument.A fixed_parameter consists of an optional set of attributes (Attributes), an optional ref, out or this modifier, a type, an identifier and an optional default_argument. Jede Fixed_parameter deklariert einen Parameter des angegebenen Typs mit dem angegebenen Namen.Each fixed_parameter declares a parameter of the given type with the given name. Die this kennzeichnet die Methode als eine Erweiterungsmethode und ist nur für den ersten Parameter einer statischen Methode zulässig.The this modifier designates the method as an extension method and is only allowed on the first parameter of a static method. Erweiterungsmethoden werden ausführlicher beschrieben Erweiterungsmethoden.Extension methods are further described in Extension methods.

Ein Fixed_parameter mit einer Default_argument heißt ein Optionaler Parameter, während eine Fixed_parameter ohne eine Default_argument ist eine Erforderlicher Parameter.A fixed_parameter with a default_argument is known as an optional parameter, whereas a fixed_parameter without a default_argument is a required parameter. Ein erforderlicher Parameter möglicherweise nicht angezeigt, nachdem ein optionaler Parameter in einer Formal_parameter_list.A required parameter may not appear after an optional parameter in a formal_parameter_list.

Ein ref oder out sind keine Parameter ein Default_argument.A ref or out parameter cannot have a default_argument. Die Ausdruck in einem Default_argument muss eine der folgenden sein:The expression in a default_argument must be one of the following:

  • a constant_expressiona constant_expression
  • Ein Ausdruck der Form new S() , in denen S ist ein Werttyp.an expression of the form new S() where S is a value type
  • Ein Ausdruck der Form default(S) , in denen S ist ein Werttyp.an expression of the form default(S) where S is a value type

Die Ausdruck muss implizit von einer Identität oder ein NULL-Werte zulassen Konvertierung in den Typ des Parameters konvertiert werden.The expression must be implicitly convertible by an identity or nullable conversion to the type of the parameter.

Wenn optionale Parameter in eine implementierende Deklaration der partiellen Methode auftreten (partielle Methoden), eine explizite Schnittstellenmember-Implementierung (explizite Implementierungen eines Schnittstellenmembers) oder in einem einzigen Parameter Indexerdeklaration (Indexer) der Compiler erhalten eine Warnung aus, da diese Member nicht auf eine Weise können, die Argumente aufgerufen werden, die ausgelassen werden können.If optional parameters occur in an implementing partial method declaration (Partial methods) , an explicit interface member implementation (Explicit interface member implementations) or in a single-parameter indexer declaration (Indexers) the compiler should give a warning, since these members can never be invoked in a way that permits arguments to be omitted.

Ein Parameter_array besteht aus einer optionalen Gruppe von Attribute (Attribute), ein params Modifizierer eine Array_type, und ein Bezeichner.A parameter_array consists of an optional set of attributes (Attributes), a params modifier, an array_type, and an identifier. Ein Parameterarray deklariert einen einzelnen Parameter des Typs angegebenen Array mit dem angegebenen Namen.A parameter array declares a single parameter of the given array type with the given name. Die Array_type eines Parameters Arrays ein eindimensionales Array sein muss (Arraytypen).The array_type of a parameter array must be a single-dimensional array type (Array types). In einem Methodenaufruf einem Parameterarray können entweder ein einzelnes Argument des Typs angegebenen Array angegeben werden, oder er lässt NULL oder mehr Argumente den Elementtyp des Arrays angegeben werden.In a method invocation, a parameter array permits either a single argument of the given array type to be specified, or it permits zero or more arguments of the array element type to be specified. Parameter-Arrays werden ausführlich in Parameterarrays.Parameter arrays are described further in Parameter arrays.

Ein Parameter_array nach einem optionalen Parameter auftreten können, jedoch keinen Standardwert – die Auslassung der Argumente für eine Parameter_array würde stattdessen bei der Erstellung eines leeren Arrays.A parameter_array may occur after an optional parameter, but cannot have a default value -- the omission of arguments for a parameter_array would instead result in the creation of an empty array.

Das folgende Beispiel veranschaulicht verschiedene Arten von Parametern:The following example illustrates different kinds of parameters:

public void M(
    ref int      i,
    decimal      d,
    bool         b = false,
    bool?        n = false,
    string       s = "Hello",
    object       o = null,
    T            t = default(T),
    params int[] a
) { }

In der Formal_parameter_list für M, i ist ein erforderliche Ref-Parameter, d Parameter ist ein erforderlicher Wert, b, s, o und t Optionale Parameter sind und a ein Parameterarray.In the formal_parameter_list for M, i is a required ref parameter, d is a required value parameter, b, s, o and t are optional value parameters and a is a parameter array.

Deklaration einer Methode erstellt einen separaten Deklarationsabschnitt für Parameter "," Parameter vom Typ "und" lokale Variablen.A method declaration creates a separate declaration space for parameters, type parameters and local variables. Namen werden in diesen Deklarationsabschnitt eingeführt, durch die Liste der Typparameter und die Liste der formalen Parameter der Methode und Deklarationen von lokalen Variablen in der Block der Methode.Names are introduced into this declaration space by the type parameter list and the formal parameter list of the method and by local variable declarations in the block of the method. Es ist ein Fehler bei zwei Mitgliedern eines Deklarationsabschnitts der Methode, die den gleichen Namen haben.It is an error for two members of a method declaration space to have the same name. Es ist ein Fehler für die Methode Deklaration und der Deklaration lokaler Variablen Speicherplatz eines geschachtelten Deklarationsabschnitts Elemente mit dem gleichen Namen enthalten.It is an error for the method declaration space and the local variable declaration space of a nested declaration space to contain elements with the same name.

Aufruf einer Methode (Methodenaufrufe) erstellt eine Kopie, die für diesen Aufruf spezifischen, weist der formalen Parameter und lokalen Variablen der Methode und der Argumentliste des Aufrufs, Werte oder Variablenverweise an das neu erstellte formalen Parameter.A method invocation (Method invocations) creates a copy, specific to that invocation, of the formal parameters and local variables of the method, and the argument list of the invocation assigns values or variable references to the newly created formal parameters. In der Block einer Methode, formalen Parameter verwiesen werden können, durch die IDs in Simple_name Ausdrücke (einfache Namen).Within the block of a method, formal parameters can be referenced by their identifiers in simple_name expressions (Simple names).

Es gibt vier Arten der formalen Parameter:There are four kinds of formal parameters:

  • Parameter, die ohne Modifizierer deklariert werden.Value parameters, which are declared without any modifiers.
  • Verweisparameter, die mit deklariert werden die ref Modifizierer.Reference parameters, which are declared with the ref modifier.
  • Output-Parameter, die mit deklariert werden die out Modifizierer.Output parameters, which are declared with the out modifier.
  • Parameterarrays, die mit deklariert werden die params Modifizierer.Parameter arrays, which are declared with the params modifier.

Siehe Signaturen und überladen, ref und out Modifizierer sind Teil der Signatur einer Methode, aber die params -Modifizierer ist nicht.As described in Signatures and overloading, the ref and out modifiers are part of a method's signature, but the params modifier is not.

Wert-ParameternValue parameters

Ein Parameter mit dem keine Modifizierer deklariert ist eine Value-Parameter.A parameter declared with no modifiers is a value parameter. Ein Wertparameter entspricht einer lokalen Variablen, die den Anfangswert von das entsprechende Argument im Aufruf Methode angegebenen erhält.A value parameter corresponds to a local variable that gets its initial value from the corresponding argument supplied in the method invocation.

Wenn ein formaler Parameter ein Werteparameter ist, muss das entsprechende Argument in einen Methodenaufruf ein Ausdruck, der implizit konvertiert werden kann (implizite Konvertierungen) in den formalen Parametertyp.When a formal parameter is a value parameter, the corresponding argument in a method invocation must be an expression that is implicitly convertible (Implicit conversions) to the formal parameter type.

Eine Methode ist zulässig, einen Wertparameter neue Werte zuweisen.A method is permitted to assign new values to a value parameter. Diese Zuweisungen wirken sich nur auf den Speicherort der lokalen Speicherressource, dargestellt durch den Wertparameter – sie haben keine Auswirkungen auf das tatsächliche Argument im Methodenaufruf angegeben.Such assignments only affect the local storage location represented by the value parameter—they have no effect on the actual argument given in the method invocation.

VerweisparameterReference parameters

Ein Parameter deklariert, mit einem ref Modifizierer ist ein Verweisparameter.A parameter declared with a ref modifier is a reference parameter. Im Gegensatz zu einem Value-Parameter erstellt ein Verweisparameter nicht auf einen neuen Speicherort zu.Unlike a value parameter, a reference parameter does not create a new storage location. Stattdessen stellt ein Verweisparameter am gleichen Speicherort wie die Variable als Argument im Methodenaufruf angegeben.Instead, a reference parameter represents the same storage location as the variable given as the argument in the method invocation.

Wenn ein formaler Parameter einen Verweisparameter handelt, muss das entsprechende Argument in einen Methodenaufruf des Schlüsselworts bestehen ref gefolgt von einem Variable_reference (präzise Regeln für die Bestimmung definitive Zuweisung) des gleichen Typs wie der formale Parameter.When a formal parameter is a reference parameter, the corresponding argument in a method invocation must consist of the keyword ref followed by a variable_reference (Precise rules for determining definite assignment) of the same type as the formal parameter. Eine Variable muss definitiv zugewiesen werden, bevor es als Verweisparameter übergeben werden kann.A variable must be definitely assigned before it can be passed as a reference parameter.

Innerhalb einer Methode gilt ein Verweisparameter immer als definitiv zugewiesen.Within a method, a reference parameter is always considered definitely assigned.

Eine Methode, die als ein Iterator deklariert (Iteratoren) keine Verweisparameter angeben.A method declared as an iterator (Iterators) cannot have reference parameters.

Im BeispielThe example

using System;

class Test
{
    static void Swap(ref int x, ref int y) {
        int temp = x;
        x = y;
        y = temp;
    }

    static void Main() {
        int i = 1, j = 2;
        Swap(ref i, ref j);
        Console.WriteLine("i = {0}, j = {1}", i, j);
    }
}

erzeugt die Ausgabeproduces the output

i = 2, j = 1

Für den Aufruf von Swap in Main, x stellt i und y stellt j.For the invocation of Swap in Main, x represents i and y represents j. Der Aufruf ist daher die Auswirkungen der Tauschen der Werte der i und j.Thus, the invocation has the effect of swapping the values of i and j.

In einer Methode, die mehrere Namen am gleichen Speicherort darstellen kann, Verweisparameter akzeptiert.In a method that takes reference parameters it is possible for multiple names to represent the same storage location. Im BeispielIn the example

class A
{
    string s;

    void F(ref string a, ref string b) {
        s = "One";
        a = "Two";
        b = "Three";
    }

    void G() {
        F(ref s, ref s);
    }
}

der Aufruf von F in G übergibt einen Verweis auf s für beide a und b.the invocation of F in G passes a reference to s for both a and b. Daher ist es bei diesen Aufruf, der die Namen s, a, und b verweisen alle auf den gleichen Speicherort aus, und die drei alle Zuweisungen Ändern des Instanzfelds s.Thus, for that invocation, the names s, a, and b all refer to the same storage location, and the three assignments all modify the instance field s.

Output-ParameterOutput parameters

Ein Parameter deklariert, mit einem out Modifizierer ist ein Output-Parameter.A parameter declared with an out modifier is an output parameter. Ein Verweisparameter ähnlich, ist ein Output-Parameter keinen neuen Speicherort erstellt werden.Similar to a reference parameter, an output parameter does not create a new storage location. Stattdessen stellt ein Output-Parameter am gleichen Speicherort wie die Variable als Argument im Methodenaufruf angegeben.Instead, an output parameter represents the same storage location as the variable given as the argument in the method invocation.

Wenn ein formaler Parameter ein Ausgabeparameter ist, muss das entsprechende Argument in einen Methodenaufruf des Schlüsselworts bestehen out gefolgt von einem Variable_reference (präzise Regeln für die Bestimmung definitive Zuweisung) des gleichen Typs wie der formale Parameter.When a formal parameter is an output parameter, the corresponding argument in a method invocation must consist of the keyword out followed by a variable_reference (Precise rules for determining definite assignment) of the same type as the formal parameter. Eine Variable muss nicht definitiv zugewiesen werden, bevor es als Output-Parameter übergeben werden kann, aber nach einem Aufruf, in dem eine Variable als Output-Parameter übergeben wurde, wird die Variable definitiv zugewiesen betrachtet.A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, the variable is considered definitely assigned.

Innerhalb einer Methode, so wie eine lokale Variable, ein Output-Parameter zunächst gilt als nicht zugewiesene und müssen definitiv zugewiesen werden, bevor der Wert verwendet wird.Within a method, just like a local variable, an output parameter is initially considered unassigned and must be definitely assigned before its value is used.

Alle Ausgabeparameter einer Methode muss definitiv zugewiesen werden, bevor die Methode zurückgibt.Every output parameter of a method must be definitely assigned before the method returns.

Eine Methode, die als partielle Methode deklariert (partielle Methoden) oder eines Iterators (Iteratoren) können keine Ausgabeparameter enthalten haben.A method declared as a partial method (Partial methods) or an iterator (Iterators) cannot have output parameters.

Output-Parameter werden in der Regel in Methoden verwendet, die Rückgabe mehrerer Werte zu erzeugen.Output parameters are typically used in methods that produce multiple return values. Zum Beispiel:For example:

using System;

class Test
{
    static void SplitPath(string path, out string dir, out string name) {
        int i = path.Length;
        while (i > 0) {
            char ch = path[i - 1];
            if (ch == '\\' || ch == '/' || ch == ':') break;
            i--;
        }
        dir = path.Substring(0, i);
        name = path.Substring(i);
    }

    static void Main() {
        string dir, name;
        SplitPath("c:\\Windows\\System\\hello.txt", out dir, out name);
        Console.WriteLine(dir);
        Console.WriteLine(name);
    }
}

Das Beispiel erzeugt die Ausgabe:The example produces the output:

c:\Windows\System\
hello.txt

Beachten Sie, dass die dir und name Variablen können nicht zugewiesen werden, vor der Übergabe an SplitPath, und dass sie als definitiv zugewiesen, nach dem Aufruf angesehen werden.Note that the dir and name variables can be unassigned before they are passed to SplitPath, and that they are considered definitely assigned following the call.

ParameterarraysParameter arrays

Ein Parameter deklariert, mit einem params Modifizierer ist ein Parameterarray.A parameter declared with a params modifier is a parameter array. Wenn eine Liste formaler Parameter ein Parameterarray enthält, muss der letzte Parameter in der Liste sein, und es muss ein eindimensionales Array-Typ aufweisen.If a formal parameter list includes a parameter array, it must be the last parameter in the list and it must be of a single-dimensional array type. Beispielsweise die Typen string[] und string[][] kann verwendet werden, wie der Typ eines Parameterarrays, aber der Typ string[,] nicht können.For example, the types string[] and string[][] can be used as the type of a parameter array, but the type string[,] can not. Es ist nicht möglich, zum Kombinieren der params Modifizierer mit den Modifizierern ref und out.It is not possible to combine the params modifier with the modifiers ref and out.

Ein Parameterarray kann die Argumente in eine von zwei Arten in einem Methodenaufruf angegeben werden:A parameter array permits arguments to be specified in one of two ways in a method invocation:

  • Das Argument angegeben wird, für ein Parameterarray kann ein einzelner Ausdruck sein, die implizit konvertiert werden kann (implizite Konvertierungen) in den Parameter-Arraytyp.The argument given for a parameter array can be a single expression that is implicitly convertible (Implicit conversions) to the parameter array type. In diesem Fall verhält sich das Parameterarray genau wie ein Value-Parameter.In this case, the parameter array acts precisely like a value parameter.
  • Der Aufruf kann auch angeben, NULL oder mehr Argumente für das Parameterarray, wobei jedes Argument ist ein Ausdruck, der implizit konvertiert werden kann (implizite Konvertierungen), die den Elementtyp des Parameterarrays.Alternatively, the invocation can specify zero or more arguments for the parameter array, where each argument is an expression that is implicitly convertible (Implicit conversions) to the element type of the parameter array. In diesem Fall der Aufruf erstellt eine Instanz des Parameterarraytyps mit einer Länge, die Anzahl von Argumenten entspricht, initialisiert die Elemente der Arrayinstanz mit den Werten des angegebenen Arguments und verwendet die neu erstellte Array-Instanz als die tatsächliche Argument.In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.

Mit Ausnahme von ermöglichen, dass eine Variable Anzahl von Argumenten in einen Aufruf, ein Parameterarray entspricht exakt dem Value-Parameter (-Wertparameter) des gleichen Typs.Except for allowing a variable number of arguments in an invocation, a parameter array is precisely equivalent to a value parameter (Value parameters) of the same type.

Im BeispielThe example

using System;

class Test
{
    static void F(params int[] args) {
        Console.Write("Array contains {0} elements:", args.Length);
        foreach (int i in args) 
            Console.Write(" {0}", i);
        Console.WriteLine();
    }

    static void Main() {
        int[] arr = {1, 2, 3};
        F(arr);
        F(10, 20, 30, 40);
        F();
    }
}

erzeugt die Ausgabeproduces the output

Array contains 3 elements: 1 2 3
Array contains 4 elements: 10 20 30 40
Array contains 0 elements:

Der erste Aufruf der F einfach das Array übergibt a als ein Value-Parameter.The first invocation of F simply passes the array a as a value parameter. Der zweite Aufruf von F erstellt automatisch eine vier-Elemente int[] mit dem angegebenen Elementwerte und übergibt, die array-Instanz als ein Value-Parameter.The second invocation of F automatically creates a four-element int[] with the given element values and passes that array instance as a value parameter. Entsprechend der dritte Aufruf von F wird ein NULL-Element erstellt int[] und übergibt diese Instanz als ein Value-Parameter.Likewise, the third invocation of F creates a zero-element int[] and passes that instance as a value parameter. Die zweite und dritte Aufrufe sind wie folgt:The second and third invocations are precisely equivalent to writing:

F(new int[] {10, 20, 30, 40});
F(new int[] {});

Bei der Auflösung von funktionsüberladungen durchführen zu können, eine Methode mit einem Parameterarray möglicherweise auf, in seiner normalen Form oder in der erweiterten Form (Anwendbarer Funktionsmember).When performing overload resolution, a method with a parameter array may be applicable either in its normal form or in its expanded form (Applicable function member). Die erweiterte Form von einer Methode ist nur dann, wenn die normale Form der Methode nicht anwendbar ist, und nur dann, wenn eine entsprechende Methode mit der gleichen Signatur wie die erweiterte Form noch nicht in denselben Typ deklariert ist verfügbar.The expanded form of a method is available only if the normal form of the method is not applicable and only if an applicable method with the same signature as the expanded form is not already declared in the same type.

Im BeispielThe example

using System;

class Test
{
    static void F(params object[] a) {
        Console.WriteLine("F(object[])");
    }

    static void F() {
        Console.WriteLine("F()");
    }

    static void F(object a0, object a1) {
        Console.WriteLine("F(object,object)");
    }

    static void Main() {
        F();
        F(1);
        F(1, 2);
        F(1, 2, 3);
        F(1, 2, 3, 4);
    }
}

erzeugt die Ausgabeproduces the output

F();
F(object[]);
F(object,object);
F(object[]);
F(object[]);

Im Beispiel sind zwei der möglichen erweiterten Formulare der Methode mit einem Parameterarray bereits in der Klasse als reguläre Methoden enthalten.In the example, two of the possible expanded forms of the method with a parameter array are already included in the class as regular methods. Diese erweiterten datenformen sind aus diesem Grund nicht berücksichtigt, wenn die Auflösung von funktionsüberladungen ausführen, und wählen Sie die erste und dritte Methodenaufrufe daher die regulären Methoden.These expanded forms are therefore not considered when performing overload resolution, and the first and third method invocations thus select the regular methods. Wenn eine Klasse eine Methode mit einem Parameterarray deklariert, ist es nicht ungewöhnlich, dass auch einige der erweiterten Formen als reguläre Methoden eingeschlossen werden sollen.When a class declares a method with a parameter array, it is not uncommon to also include some of the expanded forms as regular methods. -Instanz, die bei der erweiterten Zustand einer Methode mit einem Parameterarray tritt auf, wird aufgerufen, wodurch es möglich ist, die die Zuordnung eines Arrays zu vermeiden.By doing so it is possible to avoid the allocation of an array instance that occurs when an expanded form of a method with a parameter array is invoked.

Wenn der Typ, der ein Parameterarray ist object[], eine mögliche Mehrdeutigkeit zwischen die normale Form der Methode und der erweiterten Form für ein einzelnes entsteht object Parameter.When the type of a parameter array is object[], a potential ambiguity arises between the normal form of the method and the expended form for a single object parameter. Der Grund für die Mehrdeutigkeit ist, dass ein object[] ist selbst in den Typ implizit object.The reason for the ambiguity is that an object[] is itself implicitly convertible to type object. Die Mehrdeutigkeit stellt kein Problem, jedoch ein, da er aufgelöst werden kann, indem Sie eine Umwandlung einfügen, bei Bedarf.The ambiguity presents no problem, however, since it can be resolved by inserting a cast if needed.

Im BeispielThe example

using System;

class Test
{
    static void F(params object[] args) {
        foreach (object o in args) {
            Console.Write(o.GetType().FullName);
            Console.Write(" ");
        }
        Console.WriteLine();
    }

    static void Main() {
        object[] a = {1, "Hello", 123.456};
        object o = a;
        F(a);
        F((object)a);
        F(o);
        F((object[])o);
    }
}

erzeugt die Ausgabeproduces the output

System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double

In der ersten und letzten Aufrufen von F, die normale Form von F ist anwendbar, da eine implizite Konvertierung des Argumenttyps in den Parametertyp vorhanden ist (beide sind vom Typ object[]).In the first and last invocations of F, the normal form of F is applicable because an implicit conversion exists from the argument type to the parameter type (both are of type object[]). Daher wählt die überladungsauflösung die normale Form von F, und das Argument wird als reguläre Werteparameter übergeben.Thus, overload resolution selects the normal form of F, and the argument is passed as a regular value parameter. In der zweiten und dritten aufrufen, die normale Form von F ist nicht anwendbar, da keine implizite Konvertierung des Argumenttyps in den Parametertyp vorhanden ist (Typ object kann nicht implizit konvertiert Typ object[]).In the second and third invocations, the normal form of F is not applicable because no implicit conversion exists from the argument type to the parameter type (type object cannot be implicitly converted to type object[]). Allerdings die erweiterte Form von F gilt, damit es von der Auflösung von funktionsüberladungen aktiviert ist.However, the expanded form of F is applicable, so it is selected by overload resolution. Als Ergebnis einem Element object[] wird durch den Aufruf erstellt und das einzige Element des Arrays mit dem angegebenen Argumentwert initialisiert wird (die selbst ist ein Verweis auf ein object[]).As a result, a one-element object[] is created by the invocation, and the single element of the array is initialized with the given argument value (which itself is a reference to an object[]).

Statische Methoden und InstanzmethodenStatic and instance methods

Wenn die Deklaration einer Methode enthält einen static -Modifizierer ist, wird diese Methode wird als eine statische Methode sein.When a method declaration includes a static modifier, that method is said to be a static method. Wenn kein static Modifizierer vorhanden ist, wird die Methode wird als eine Instanzmethode sein.When no static modifier is present, the method is said to be an instance method.

Eine statische Methode in einer bestimmten Instanz kann nicht ausgeführt werden, und es ist ein Fehler während der Kompilierung zum Verweisen auf this in einer statischen Methode.A static method does not operate on a specific instance, and it is a compile-time error to refer to this in a static method.

Eine Instanzmethode funktioniert für eine bestimmte Instanz einer Klasse, und diese Instanz zugegriffen werden kann, als this (diesen Zugriff).An instance method operates on a given instance of a class, and that instance can be accessed as this (This access).

Wenn eine Methode verwiesen wird, einem Member_access (Memberzugriff) des Formulars E.M, wenn M ist eine statische Methode, E muss einen Typ mit deutenM, und wenn M ist eine Instanzmethode E muss eine Instanz von einem Typ mit deuten M.When a method is referenced in a member_access (Member access) of the form E.M, if M is a static method, E must denote a type containing M, and if M is an instance method, E must denote an instance of a type containing M.

Die Unterschiede zwischen statischen und Instanzmember finden Sie weiter unten in statische und Instanzmember.The differences between static and instance members are discussed further in Static and instance members.

Virtuelle MethodenVirtual methods

Wenn eine Instanzmethodendeklaration enthält eine virtual -Modifizierer ist, wird diese Methode wird als eine virtuelle Methode sein.When an instance method declaration includes a virtual modifier, that method is said to be a virtual method. Wenn kein virtual Modifizierer vorhanden ist, wird die Methode ist eine nicht virtuelle Methode bezeichnet.When no virtual modifier is present, the method is said to be a non-virtual method.

Die Implementierung einer nicht virtuellen Methode ist unveränderlich: Die Implementierung ist identisch, ob die Methode, auf einer Instanz der Klasse in aufgerufen wird der sie deklariert ist, oder eine Instanz einer abgeleiteten Klasse.The implementation of a non-virtual method is invariant: The implementation is the same whether the method is invoked on an instance of the class in which it is declared or an instance of a derived class. Im Gegensatz dazu kann die Implementierung einer virtuellen Methode durch abgeleitete Klassen abgelöst werden.In contrast, the implementation of a virtual method can be superseded by derived classes. Der Prozess der Implementierung einer geerbten virtuellen Methode heißt überschreiben diese Methode (Methoden außer Kraft setzen).The process of superseding the implementation of an inherited virtual method is known as overriding that method (Override methods).

Im Aufruf einer virtuellen Methode die Laufzeittyp der Instanz, die diesen Aufruf benötigt, direkten legt fest, die Implementierung der tatsächlichen Methode aufrufen.In a virtual method invocation, the run-time type of the instance for which that invocation takes place determines the actual method implementation to invoke. Im Aufruf einer nicht virtuellen Methode die Kompilierzeittyp der Instanz ist der bestimmende Faktor.In a non-virtual method invocation, the compile-time type of the instance is the determining factor. Genau bedeutet dies, wenn eine Methode namens N wird aufgerufen, mit einer Argumentliste A auf einer Instanz mit einem Typ während der Kompilierung C und einen Laufzeittyp R (, in dem R ist entweder C oder eine abgeleitete Klasse von C), der Aufruf wird wie folgt verarbeitet:In precise terms, when a method named N is invoked with an argument list A on an instance with a compile-time type C and a run-time type R (where R is either C or a class derived from C), the invocation is processed as follows:

  • Zunächst wird die Auflösung von funktionsüberladungen auf angewendet C, N, und A, auswählen eine bestimmte Methode M aus dem Satz von Methoden deklariert "und" geerbt C.First, overload resolution is applied to C, N, and A, to select a specific method M from the set of methods declared in and inherited by C. Finden Sie im Methodenaufrufe.This is described in Method invocations.
  • Wenn danach M ist eine nicht virtuelle Methode, M aufgerufen wird.Then, if M is a non-virtual method, M is invoked.
  • Andernfalls M ist eine virtuelle Methode und der am weitesten abgeleiteten Implementierung der M in Bezug auf R aufgerufen wird.Otherwise, M is a virtual method, and the most derived implementation of M with respect to R is invoked.

Für jede virtuelle Methode von einer Klasse deklariert oder geerbt, vorhanden ist eine am weitesten abgeleiteten Implementierung der Methode in Bezug auf die Klasse.For every virtual method declared in or inherited by a class, there exists a most derived implementation of the method with respect to that class. Die am weitesten abgeleiteten Implementierung einer virtuellen Methode M in Bezug auf eine Klasse R wird wie folgt bestimmt:The most derived implementation of a virtual method M with respect to a class R is determined as follows:

  • Wenn R enthält, die Einführung von virtual Deklaration M, ist dies der am weitesten abgeleiteten Implementierung der M.If R contains the introducing virtual declaration of M, then this is the most derived implementation of M.
  • Andernfalls gilt: Wenn R enthält ein override von M, ist dies der am weitesten abgeleiteten Implementierung der M.Otherwise, if R contains an override of M, then this is the most derived implementation of M.
  • Andernfalls am meisten Implementierung der abgeleiteten der M in Bezug auf R ist identisch mit den am weitesten abgeleiteten Implementierung der M in Bezug auf die direkte Basisklasse von R.Otherwise, the most derived implementation of M with respect to R is the same as the most derived implementation of M with respect to the direct base class of R.

Im folgende Beispiel werden die Unterschiede zwischen virtuellen und nicht virtuelle Methoden veranschaulicht:The following example illustrates the differences between virtual and non-virtual methods:

using System;

class A
{
    public void F() { Console.WriteLine("A.F"); }

    public virtual void G() { Console.WriteLine("A.G"); }
}

class B: A
{
    new public void F() { Console.WriteLine("B.F"); }

    public override void G() { Console.WriteLine("B.G"); }
}

class Test
{
    static void Main() {
        B b = new B();
        A a = b;
        a.F();
        b.F();
        a.G();
        b.G();
    }
}

Im Beispiel A führt eine nicht virtuelle Methode F und eine virtuelle Methode G.In the example, A introduces a non-virtual method F and a virtual method G. Die Klasse B führt eine neue nicht virtuelle Methode F, daher durch das Ausblenden der geerbten F, und außerdem überschreibt die geerbte Methode G.The class B introduces a new non-virtual method F, thus hiding the inherited F, and also overrides the inherited method G. Das Beispiel erzeugt die Ausgabe:The example produces the output:

A.F
B.F
B.G
B.G

Beachten Sie, dass die Anweisung a.G() ruft B.G, nicht A.G.Notice that the statement a.G() invokes B.G, not A.G. Dies ist, da der Laufzeittyp der Instanz (d.h. B), nicht der Kompilierzeit-Typ der Instanz (d.h. A), bestimmt die Implementierung der tatsächlichen Methode zum Aufrufen.This is because the run-time type of the instance (which is B), not the compile-time type of the instance (which is A), determines the actual method implementation to invoke.

Da die Methoden zum Ausblenden von geerbter Methoden zulässig sind, ist es möglich, eine Klasse kann mehrere virtuelle Methoden mit derselben Signatur enthalten.Because methods are allowed to hide inherited methods, it is possible for a class to contain several virtual methods with the same signature. Dies ist keiner Mehrdeutigkeiten, da alle bis auf die am häufigsten abgerufene Methode ausgeblendet sind.This does not present an ambiguity problem, since all but the most derived method are hidden. Im BeispielIn the example

using System;

class A
{
    public virtual void F() { Console.WriteLine("A.F"); }
}

class B: A
{
    public override void F() { Console.WriteLine("B.F"); }
}

class C: B
{
    new public virtual void F() { Console.WriteLine("C.F"); }
}

class D: C
{
    public override void F() { Console.WriteLine("D.F"); }
}

class Test
{
    static void Main() {
        D d = new D();
        A a = d;
        B b = d;
        C c = d;
        a.F();
        b.F();
        c.F();
        d.F();
    }
}

die C und D Klassen enthalten, zwei virtuelle Methoden, mit der gleichen Signatur: Der eingeschleuste A und der eingeschleuste C.the C and D classes contain two virtual methods with the same signature: The one introduced by A and the one introduced by C. Die Methode, die von eingeführte C Blendet die geerbte Methode A.The method introduced by C hides the method inherited from A. Daher die außer Kraft setzen-Deklaration in D überschreibt die Methode, die von eingeführt C, und es ist nicht möglich, dass D , die Methode eingeführt, durch Überschreiben A.Thus, the override declaration in D overrides the method introduced by C, and it is not possible for D to override the method introduced by A. Das Beispiel erzeugt die Ausgabe:The example produces the output:

B.F
B.F
D.F
D.F

Beachten Sie, dass es möglich ist, rufen Sie die virtuelle Methode die ausgeblendete durch den Zugriff auf eine Instanz von D über einen weniger abgeleiteten Typ, die in der die Methode nicht ausgeblendet ist.Note that it is possible to invoke the hidden virtual method by accessing an instance of D through a less derived type in which the method is not hidden.

Methoden außer Kraft setzenOverride methods

Wenn eine Instanzmethodendeklaration enthält ein override Modifizierer, die Methode gilt eine Überschreibungsmethode.When an instance method declaration includes an override modifier, the method is said to be an override method. Eine Überschreibungsmethode überschreibt eine geerbte virtuelle Methode mit der gleichen Signatur.An override method overrides an inherited virtual method with the same signature. Während eine Deklaration einer virtuellen Methode eine neue Methode einführt, spezialisiert eine Deklaration einer überschriebenen Methode eine vorhandene geerbte virtuelle Methode, indem eine neue Implementierung dieser Methode bereitgestellt wird.Whereas a virtual method declaration introduces a new method, an override method declaration specializes an existing inherited virtual method by providing a new implementation of that method.

Die Methode überschrieben, indem ein override Deklaration wird als bezeichnet die Basismethode überschreiben.The method overridden by an override declaration is known as the overridden base method. Für eine Überschreibungsmethode M in einer Klasse deklarierten C, die überschriebene Basismethode richtet sich nach der Untersuchung jeder Typ von der Basisklasse C, beginnend mit dem direkten Basisklasse C und mit jedem aufeinander folgenden direkte Basisklasse-Typ, bis in einem angegebenen Basisklassentyp mindestens eine zugängliche Methode ist die befindet, hat die gleiche Signatur wie M nach dem Ersetzen der Typargumente.For an override method M declared in a class C, the overridden base method is determined by examining each base class type of C, starting with the direct base class type of C and continuing with each successive direct base class type, until in a given base class type at least one accessible method is located which has the same signature as M after substitution of type arguments. Im Rahmen, suchen die überschriebene Basismethode, eine Methode wird als verfügbar betrachtet, ist dies public, sofern sie protected, sofern sie protected internal, oder es ist internal und im selben Programm als deklariert C.For the purposes of locating the overridden base method, a method is considered accessible if it is public, if it is protected, if it is protected internal, or if it is internal and declared in the same program as C.

Ein Fehler während der Kompilierung tritt auf, es sei denn, alle der folgenden "true" für eine Deklaration außer Kraft setzen:A compile-time error occurs unless all of the following are true for an override declaration:

  • Eine überschriebene Basismethode kann gefunden werden, wie oben beschrieben werden.An overridden base method can be located as described above.
  • Es gibt genau einen solchen überschriebene Basismethode.There is exactly one such overridden base method. Diese Einschränkung wirkt sich nur, wenn Sie der Basisklassentyp ein konstruierter Typ ist, macht die Ersetzung der Argumente des Typs der Signatur der beiden Methoden identisch.This restriction has effect only if the base class type is a constructed type where the substitution of type arguments makes the signature of two methods the same.
  • Die überschriebene Basismethode ist einer virtuell, abstrakt oder Überschreiben der Methode.The overridden base method is a virtual, abstract, or override method. Die überschriebene Basismethode darf nicht in anderen Worten: statisch oder nicht virtuell sein.In other words, the overridden base method cannot be static or non-virtual.
  • Die überschriebene Basismethode ist keine versiegelten Methode.The overridden base method is not a sealed method.
  • Die Methode zum Überschreiben und die überschriebene Basismethode haben den gleichen Rückgabetyp auf.The override method and the overridden base method have the same return type.
  • Die Deklaration außer Kraft setzen und die überschriebene Basismethode haben die gleiche deklarierte Zugriffsart auf.The override declaration and the overridden base method have the same declared accessibility. Eine außer Kraft setzen-Deklaration kann nicht in anderen Worten, den Zugriff auf die virtuelle Methode ändern.In other words, an override declaration cannot change the accessibility of the virtual method. Allerdings muss, wenn die überschriebene Basismethode wird intern geschützt, und sie in einer anderen Assembly deklariert wird, als die Assembly mit der Methode außer Kraft setzen und dann der Überschreibungsmethode deklariert Zugriff geschützt werden.However, if the overridden base method is protected internal and it is declared in a different assembly than the assembly containing the override method then the override method's declared accessibility must be protected.
  • Die außer Kraft setzen-Deklaration ist nicht mit Typ-Parameter-Einschränkungen-Klauseln angegeben.The override declaration does not specify type-parameter-constraints-clauses. Stattdessen werden die Einschränkungen von die überschriebene Basismethode geerbt.Instead the constraints are inherited from the overridden base method. Beachten Sie, dass die Einschränkungen, die Typparameter in der überschriebenen Methode sind in der geerbten Einschränkung durch Typargumente ersetzt werden können.Note that constraints that are type parameters in the overridden method may be replaced by type arguments in the inherited constraint. Dies kann zu Einschränkungen führen, die nicht gültig, wenn explizit angegeben, z. B. Werttypen oder versiegelte Typen sind.This can lead to constraints that are not legal when explicitly specified, such as value types or sealed types.

Das folgende Beispiel zeigt, wie die überschreibenden Regeln für generische Klassen funktionieren:The following example demonstrates how the overriding rules work for generic classes:

abstract class C<T>
{
    public virtual T F() {...}
    public virtual C<T> G() {...}
    public virtual void H(C<T> x) {...}
}

class D: C<string>
{
    public override string F() {...}            // Ok
    public override C<string> G() {...}         // Ok
    public override void H(C<T> x) {...}        // Error, should be C<string>
}

class E<T,U>: C<U>
{
    public override U F() {...}                 // Ok
    public override C<U> G() {...}              // Ok
    public override void H(C<T> x) {...}        // Error, should be C<U>
}

Eine Deklaration für die Außerkraftsetzung stehen die überschriebene Basismethode mithilfe einer Base_access (Base Access).An override declaration can access the overridden base method using a base_access (Base access). Im BeispielIn the example

class A
{
    int x;

    public virtual void PrintFields() {
        Console.WriteLine("x = {0}", x);
    }
}

class B: A
{
    int y;

    public override void PrintFields() {
        base.PrintFields();
        Console.WriteLine("y = {0}", y);
    }
}

die base.PrintFields() Aufruf im B Ruft die PrintFields Methode deklariert A.the base.PrintFields() invocation in B invokes the PrintFields method declared in A. Ein Base_access den virtuellen Aufruf-Mechanismus deaktiviert und einfach die Basismethode behandelt, als eine nicht virtuelle Methode.A base_access disables the virtual invocation mechanism and simply treats the base method as a non-virtual method. Hatte den Aufruf im B wurde geschrieben ((A)this).PrintFields(), wäre Sie rekursiv Aufrufen der PrintFields Methode deklariert werden, B, nicht zu derjenigen, die in deklariert A, da PrintFields ist virtuell und den Laufzeittyp der ((A)this) ist B.Had the invocation in B been written ((A)this).PrintFields(), it would recursively invoke the PrintFields method declared in B, not the one declared in A, since PrintFields is virtual and the run-time type of ((A)this) is B.

Nur durch Einfügen einer override Modifizierer kann eine Methode eine andere Methode zu überschreiben.Only by including an override modifier can a method override another method. In allen anderen Fällen wird eine Methode mit der gleichen Signatur wie eine geerbte Methode einfach die geerbte Methode ausgeblendet.In all other cases, a method with the same signature as an inherited method simply hides the inherited method. Im BeispielIn the example

class A
{
    public virtual void F() {}
}

class B: A
{
    public virtual void F() {}        // Warning, hiding inherited F()
}

die F -Methode in der B enthält kein override Modifizierer und wird daher nicht überschrieben der F -Methode in der A.the F method in B does not include an override modifier and therefore does not override the F method in A. Vielmehr die F -Methode in der B Blendet die Methode in A, und eine Warnung wird ausgegeben, da die Deklaration keine umfasst eine new Modifizierer.Rather, the F method in B hides the method in A, and a warning is reported because the declaration does not include a new modifier.

Im BeispielIn the example

class A
{
    public virtual void F() {}
}

class B: A
{
    new private void F() {}        // Hides A.F within body of B
}

class C: B
{
    public override void F() {}    // Ok, overrides A.F
}

die F -Methode in der B verbirgt den virtuellen F Methode geerbt von A.the F method in B hides the virtual F method inherited from A. Das neue F in B privaten Zugriff, der Bereich enthält nur die Klassendefinition von B und erstreckt sich nicht um C.Since the new F in B has private access, its scope only includes the class body of B and does not extend to C. Daher ist die Deklaration der F in C ist zulässig, außer Kraft setzen der F vererbt A.Therefore, the declaration of F in C is permitted to override the F inherited from A.

Versiegelte MethodenSealed methods

Wenn eine Instanzmethodendeklaration enthält eine sealed -Modifizierer ist, wird diese Methode wird als bezeichnet ein versiegelt Methode.When an instance method declaration includes a sealed modifier, that method is said to be a sealed method. Wenn eine Instanzmethodendeklaration enthält die sealed Modifizierer verwenden, muss auch enthalten die override Modifizierer.If an instance method declaration includes the sealed modifier, it must also include the override modifier. Verwenden der sealed -Modifizierer wird verhindert, dass eine abgeleitete Klasse weiter durch Überschreiben der Methode.Use of the sealed modifier prevents a derived class from further overriding the method.

Im BeispielIn the example

using System;

class A
{
    public virtual void F() {
        Console.WriteLine("A.F");
    }

    public virtual void G() {
        Console.WriteLine("A.G");
    }
}

class B: A
{
    sealed override public void F() {
        Console.WriteLine("B.F");
    } 

    override public void G() {
        Console.WriteLine("B.G");
    } 
}

class C: B
{
    override public void G() {
        Console.WriteLine("C.G");
    } 
}

die Klasse B bietet zwei Methoden außer Kraft setzen: eine F Methode, die sealed Modifizierer und eine G -Methode, die nicht der Fall ist.the class B provides two override methods: an F method that has the sealed modifier and a G method that does not. Bdie Nutzung von der versiegelten modifier wird verhindert, dass C weiter überschreiben F.B's use of the sealed modifier prevents C from further overriding F.

Abstrakte MethodenAbstract methods

Wenn eine Instanzmethodendeklaration enthält ein abstract -Modifizierer ist, wird diese Methode wird als bezeichnet ein abstrakte Methode.When an instance method declaration includes an abstract modifier, that method is said to be an abstract method. Obwohl eine abstrakte Methode implizit auch eine virtuelle Methode ist, können keine Modifizierer besitzen virtual.Although an abstract method is implicitly also a virtual method, it cannot have the modifier virtual.

Eine abstrakte Methodendeklaration führt eine neue virtuelle Methode, aber es bietet eine Implementierung dieser Methode keine.An abstract method declaration introduces a new virtual method but does not provide an implementation of that method. Stattdessen müssen nicht abstrakte abgeleitete Klassen ihre eigene Implementierung bereitstellen, indem Sie diese Methode überschreiben.Instead, non-abstract derived classes are required to provide their own implementation by overriding that method. Da eine abstrakte Methode keine Implementierungen, bietet der Method_body einer abstrakten Methode einfach besteht aus einem Semikolon.Because an abstract method provides no actual implementation, the method_body of an abstract method simply consists of a semicolon.

Abstrakte Methodendeklarationen sind nur in abstrakten Klassen zulässig (abstrakte Klassen).Abstract method declarations are only permitted in abstract classes (Abstract classes).

Im BeispielIn the example

public abstract class Shape
{
    public abstract void Paint(Graphics g, Rectangle r);
}

public class Ellipse: Shape
{
    public override void Paint(Graphics g, Rectangle r) {
        g.DrawEllipse(r);
    }
}

public class Box: Shape
{
    public override void Paint(Graphics g, Rectangle r) {
        g.DrawRect(r);
    }
}

die Shape -Klasse definiert die abstrakte Vorstellung einer geometrischen Formobjekt, das sich selbst zu zeichnen kann.the Shape class defines the abstract notion of a geometrical shape object that can paint itself. Die Paint Methode ist abstrakt, da es keine sinnvolle Standardimplementierung ist.The Paint method is abstract because there is no meaningful default implementation. Die Ellipse und Box Klassen sind konkrete Shape Implementierungen.The Ellipse and Box classes are concrete Shape implementations. Da diese Klassen abstrakt sind, müssen sie außer Kraft setzen der Paint Methode und eine tatsächliche Implementierung bereitstellen.Because these classes are non-abstract, they are required to override the Paint method and provide an actual implementation.

Es ist ein Fehler während der Kompilierung für eine Base_access (Base Access) auf eine abstrakte Methode zu verweisen.It is a compile-time error for a base_access (Base access) to reference an abstract method. Im BeispielIn the example

abstract class A
{
    public abstract void F();
}

class B: A
{
    public override void F() {
        base.F();                        // Error, base.F is abstract
    }
}

ein Kompilierung ein Fehler wird gemeldet, für die base.F() aufrufen, da es sich um eine abstrakte Methode verweist.a compile-time error is reported for the base.F() invocation because it references an abstract method.

Eine abstrakte Methodendeklaration ist zulässig, um eine virtuelle Methode zu überschreiben.An abstract method declaration is permitted to override a virtual method. Dadurch können eine abstrakte Klasse, die erneute Implementierung der Methode in abgeleiteten Klassen zu erzwingen, und die ursprüngliche Implementierung der Methode nicht verfügbar.This allows an abstract class to force re-implementation of the method in derived classes, and makes the original implementation of the method unavailable. Im BeispielIn the example

using System;

class A
{
    public virtual void F() {
        Console.WriteLine("A.F");
    }
}

abstract class B: A
{
    public abstract override void F();
}

class C: B
{
    public override void F() {
        Console.WriteLine("C.F");
    }
}

Klasse A deklariert eine virtuelle Methode, Klasse B überschreibt diese Methode mit dem eine abstrakte Methode, und die Klasse C überschreibt die abstrakte Methode, um eine eigene Implementierung bereitzustellen.class A declares a virtual method, class B overrides this method with an abstract method, and class C overrides the abstract method to provide its own implementation.

Externe MethodenExternal methods

Wenn eine Methodendeklaration enthält ein extern -Modifizierer ist, wird diese Methode wird als bezeichnet ein externe Methode.When a method declaration includes an extern modifier, that method is said to be an external method. Externe Methoden werden extern implementiert, in der Regel mit einer anderen Sprache als C# -Code.External methods are implemented externally, typically using a language other than C#. Da eine externe Methodendeklaration keine Implementierungen, bietet der Method_body besteht aus einer externen Methode einfach aus einem Semikolon.Because an external method declaration provides no actual implementation, the method_body of an external method simply consists of a semicolon. Eine externe Methode kann nicht generisch sein.An external method may not be generic.

Die extern Modifizierer wird normalerweise verwendet, in Verbindung mit einer DllImport Attribut (Interoperation mit COM- und Win32-Komponenten), können externe Methoden von DLLs (Dynamic Link Libraries) implementiert werden.The extern modifier is typically used in conjunction with a DllImport attribute (Interoperation with COM and Win32 components), allowing external methods to be implemented by DLLs (Dynamic Link Libraries). Die ausführungsumgebung möglicherweise andere Mechanismen unterstützt durch Implementierungen der externe Methoden bereitgestellt werden kann.The execution environment may support other mechanisms whereby implementations of external methods can be provided.

Wenn eine externe Methode enthält einen DllImport -Attribut, die Deklaration der Methode muss auch enthalten eine static Modifizierer.When an external method includes a DllImport attribute, the method declaration must also include a static modifier. Dieses Beispiel veranschaulicht die Verwendung von der extern Modifizierer und der DllImport Attribut:This example demonstrates the use of the extern modifier and the DllImport attribute:

using System.Text;
using System.Security.Permissions;
using System.Runtime.InteropServices;

class Path
{
    [DllImport("kernel32", SetLastError=true)]
    static extern bool CreateDirectory(string name, SecurityAttribute sa);

    [DllImport("kernel32", SetLastError=true)]
    static extern bool RemoveDirectory(string name);

    [DllImport("kernel32", SetLastError=true)]
    static extern int GetCurrentDirectory(int bufSize, StringBuilder buf);

    [DllImport("kernel32", SetLastError=true)]
    static extern bool SetCurrentDirectory(string name);
}

Partielle Methoden (Zusammenfassung)Partial methods (recap)

Wenn die Deklaration einer Methode enthält einen partial -Modifizierer ist, wird diese Methode wird als bezeichnet ein partielle Methode.When a method declaration includes a partial modifier, that method is said to be a partial method. Partielle Methoden können nur Mitglieder der partiellen Typen deklariert werden (partielle Typen), und eine Reihe von Einschränkungen unterliegen.Partial methods can only be declared as members of partial types (Partial types), and are subject to a number of restrictions. Partielle Methoden ausführlicher beschrieben werden partielle Methoden.Partial methods are further described in Partial methods.

ErweiterungsmethodenExtension methods

Wenn der erste Parameter einer Methode enthält die this -Modifizierer ist, wird diese Methode wird als bezeichnet ein Erweiterungsmethode.When the first parameter of a method includes the this modifier, that method is said to be an extension method. Erweiterungsmethoden können nur in nicht-generische, nicht geschachtelten statischen Klassen deklariert werden.Extension methods can only be declared in non-generic, non-nested static classes. Der erste Parameter einer Erweiterungsmethode haben keine Modifizierer außer this, und der Parametertyp kann kein Zeigertyp sein.The first parameter of an extension method can have no modifiers other than this, and the parameter type cannot be a pointer type.

Im folgenden finden ein Beispiel für eine statische Klasse, die zwei Erweiterungsmethoden deklariert:The following is an example of a static class that declares two extension methods:

public static class Extensions
{
    public static int ToInt32(this string s) {
        return Int32.Parse(s);
    }

    public static T[] Slice<T>(this T[] source, int index, int count) {
        if (index < 0 || count < 0 || source.Length - index < count)
            throw new ArgumentException();
        T[] result = new T[count];
        Array.Copy(source, index, result, 0, count);
        return result;
    }
}

Eine Erweiterungsmethode ist eine normale statische Methode.An extension method is a regular static method. Darüber hinaus im Gültigkeitsbereich der einschließenden statische Klasse ist, eine Erweiterungsmethode kann aufgerufen werden mithilfe einer Instanzmethodensyntax Aufruf (Erweiterung Methodenaufrufe), mit dem Empfänger-Ausdruck als erstes Argument.In addition, where its enclosing static class is in scope, an extension method can be invoked using instance method invocation syntax (Extension method invocations), using the receiver expression as the first argument.

Das folgende Programm verwendet die Erweiterungsmethoden, die oben deklariert:The following program uses the extension methods declared above:

static class Program
{
    static void Main() {
        string[] strings = { "1", "22", "333", "4444" };
        foreach (string s in strings.Slice(1, 2)) {
            Console.WriteLine(s.ToInt32());
        }
    }
}

Die Slice Methode steht für die string[], und die ToInt32 Methode steht für string, da sie als Erweiterungsmethoden deklariert wurden.The Slice method is available on the string[], and the ToInt32 method is available on string, because they have been declared as extension methods. Die Bedeutung des Programms ist identisch mit den folgenden, wobei normale statische Methodenaufrufen:The meaning of the program is the same as the following, using ordinary static method calls:

static class Program
{
    static void Main() {
        string[] strings = { "1", "22", "333", "4444" };
        foreach (string s in Extensions.Slice(strings, 1, 2)) {
            Console.WriteLine(Extensions.ToInt32(s));
        }
    }
}

MethodentextMethod body

Die Method_body Deklaration einer Methode besteht aus einer Blocktext, einen ausdruckskörper oder ein Semikolon.The method_body of a method declaration consists of either a block body, an expression body or a semicolon.

Die Ergebnistyp einer Methode ist void ist der Rückgabetyp void, oder wenn die Methode asynchron ist und der Rückgabetyp ist System.Threading.Tasks.Task.The result type of a method is void if the return type is void, or if the method is async and the return type is System.Threading.Tasks.Task. Andernfalls ist der Ergebnistyp einer nicht-Async-Methode, der Rückgabetyp und dem Rückgabetyp einer Async-Methode mit Rückgabetyp System.Threading.Tasks.Task<T> ist T.Otherwise, the result type of a non-async method is its return type, and the result type of an async method with return type System.Threading.Tasks.Task<T> is T.

Wenn eine Methode verfügt über eine void dazu führen, Typ und einem Blocktext return Anweisungen (die return-Anweisung) im-Block dürfen nicht auf einen Ausdruck angeben.When a method has a void result type and a block body, return statements (The return statement) in the block are not permitted to specify an expression. Wenn die Ausführung des Blocks einer "void" Methode normal abgeschlossen wird (d. h. Kontrollflüsse am Ende des Methodentexts), dass die Methode einfach an den aktuellen Aufrufer zurückgibt.If execution of the block of a void method completes normally (that is, control flows off the end of the method body), that method simply returns to its current caller.

Wenn eine Methode verfügt über eine void Ergebnis und einen ausdruckskörper, den Ausdruck E muss eine Statement_expression, und der Text entspricht genau einen Blocktext des Formulars { E; }.When a method has a void result and an expression body, the expression E must be a statement_expression, and the body is exactly equivalent to a block body of the form { E; }.

Wenn eine Methode einen für nicht-Void-Ergebnistyp und einem Block Anforderungstext, jede return -Anweisung in den Block muss einen Ausdruck, der implizit in den Ergebnistyp konvertiert werden angeben.When a method has a non-void result type and a block body, each return statement in the block must specify an expression that is implicitly convertible to the result type. Der Endpunkt eines Block-Texts, der eine Methode einen Wert zurückgibt, darf nicht erreichbar sein.The endpoint of a block body of a value-returning method must not be reachable. Das heißt, in einer Methode Wertrückgabe mit einem Blocktext von Steuerelement darf nicht über das Ende des Methodentexts hinausgehen.In other words, in a value-returning method with a block body, control is not permitted to flow off the end of the method body.

Wenn eine Methode ein für nicht-Void-Ergebnistyp und einen ausdruckskörper hat, der Ausdruck implizit in den Ergebnistyp konvertiert werden muss und der Text genau einen Blocktext des Formulars entspricht { return E; }.When a method has a non-void result type and an expression body, the expression must be implicitly convertible to the result type, and the body is exactly equivalent to a block body of the form { return E; }.

Im BeispielIn the example

class A
{
    public int F() {}            // Error, return value required

    public int G() {
        return 1;
    }

    public int H(bool b) {
        if (b) {
            return 1;
        }
        else {
            return 0;
        }
    }

    public int I(bool b) => b ? 1 : 0;
}

die Wertrückgabe F Methode führt ein Fehler während der Kompilierung, da das Ende des Methodentexts ablaufsteuerung können.the value-returning F method results in a compile-time error because control can flow off the end of the method body. Die G und H Methoden richtig sind, da sämtliche möglichen ausführungswege eine return-Anweisung enden, der angibt, einen Wert zurückgegeben.The G and H methods are correct because all possible execution paths end in a return statement that specifies a return value. Die I Methode korrekt ist, da Text einen Anweisungsblock mit nur eine einzelne rückgabeanweisung darin entspricht.The I method is correct, because its body is equivalent to a statement block with just a single return statement in it.

MethodenüberladungMethod overloading

Die Regeln der überladungsauflösung Methode werden in beschrieben Typrückschluss.The method overload resolution rules are described in Type inference.

EigenschaftenProperties

Ein Eigenschaft ist ein Element, das Zugriff auf ein Merkmal eines Objekts oder einer Klasse bereitstellt.A property is a member that provides access to a characteristic of an object or a class. Beispiele für Eigenschaften enthalten die Länge einer Zeichenfolge, die Größe einer Schriftart, die Titelleiste eines Fensters, den Namen eines Kunden und so weiter.Examples of properties include the length of a string, the size of a font, the caption of a window, the name of a customer, and so on. Eigenschaften sind eine natürliche Erweiterung von Feldern, beide sind benannte Member mit zugeordneten Typen, und die Syntax für den Zugriff auf Felder und Eigenschaften entspricht.Properties are a natural extension of fields—both are named members with associated types, and the syntax for accessing fields and properties is the same. Im Gegensatz zu Feldern bezeichnen Eigenschaften jedoch keine Speicherorte.However, unlike fields, properties do not denote storage locations. Stattdessen verfügen Eigenschaften über Accessors zum Angeben der Anweisungen, die beim Lesen oder Schreiben ihrer Werte ausgeführt werden sollen.Instead, properties have accessors that specify the statements to be executed when their values are read or written. Eigenschaften stellen somit einen Mechanismus zum Zuordnen von Aktionen mit dem Lesen und Schreiben der Attribute eines Objekts bereit; Außerdem ermöglichen sie solche Attribute berechnet werden soll.Properties thus provide a mechanism for associating actions with the reading and writing of an object's attributes; furthermore, they permit such attributes to be computed.

Eigenschaften werden deklariert, die mit Property_declarations:Properties are declared using property_declarations:

property_declaration
    : attributes? property_modifier* type member_name property_body
    ;

property_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | property_modifier_unsafe
    ;

property_body
    : '{' accessor_declarations '}' property_initializer?
    | '=>' expression ';'
    ;

property_initializer
    : '=' variable_initializer ';'
    ;

Ein Property_declaration eventuell einen Satz von Attribute (Attribute) und eine gültige Kombination der vier Zugriffsmodifizierer (Zugriffsmodifizierer ), wird die new (der new-Modifizierer), static (statische und Instanzmethoden), virtual (virtuelle Methoden), override (Methoden außer Kraft setzen), sealed (Versiegelte Methoden), abstract (abstrakten Methoden), und extern (Externe Methoden) Modifizierer.A property_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), static (Static and instance methods), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

Eigenschaftendeklarationen gelten dieselben Regeln wie Methodendeklarationen (Methoden) im Hinblick auf die gültigen Kombinationen der Modifizierer.Property declarations are subject to the same rules as method declarations (Methods) with regard to valid combinations of modifiers.

Die Typ Deklaration gibt den Typ der Eigenschaft, der durch die Deklaration einer Eigenschaft an und Member_name gibt den Namen der Eigenschaft.The type of a property declaration specifies the type of the property introduced by the declaration, and the member_name specifies the name of the property. Wenn die Eigenschaft eine explizite Schnittstellenmember-Implementierung, ist die Member_name ist einfach ein Bezeichner.Unless the property is an explicit interface member implementation, the member_name is simply an identifier. Für eine explizite Schnittstellenmember-Implementierung (explizite Implementierungen eines Schnittstellenmembers), wird die Member_name besteht aus einer Interface_type gefolgt von einer " ."und ein Bezeichner.For an explicit interface member implementation (Explicit interface member implementations), the member_name consists of an interface_type followed by a "." and an identifier.

Die Typ einer Eigenschaft muss mindestens dieselben zugriffsmöglichkeiten bieten wie die Eigenschaft selbst (Barrierefreiheit Einschränkungen).The type of a property must be at least as accessible as the property itself (Accessibility constraints).

Ein Property_body entweder besteht möglicherweise aus einem Accessor-Body oder ausdruckskörper.A property_body may either consist of an accessor body or an expression body. In einem Accessortext Accessor_declarations, die eingeschlossen werden müssen, "{"und"}" Token, deklarieren die Accessoren (Accessoren) der Eigenschaft.In an accessor body, accessor_declarations, which must be enclosed in "{" and "}" tokens, declare the accessors (Accessors) of the property. Die Accessoren angeben, die ausführbaren Anweisungen lesen und schreiben die Eigenschaft zugeordnet wird.The accessors specify the executable statements associated with reading and writing the property.

Ein ausdruckskörper bestehend aus => gefolgt von einer Ausdruck E und ein Semikolon entspricht genau der Anweisungstext { get { return E; } }, und kann daher nur nur-Getter an verwendet werden Eigenschaften, in dem das Ergebnis der getter-Methode von einem einzelnen Ausdruck angegeben ist.An expression body consisting of => followed by an expression E and a semicolon is exactly equivalent to the statement body { get { return E; } }, and can therefore only be used to specify getter-only properties where the result of the getter is given by a single expression.

Ein Property_initializer kann nur für eine automatisch implementierte Eigenschaft zugewiesen werden (automatisch implementierten Eigenschaften), und bewirkt, dass die Initialisierung des zugrunde liegenden Felds solcher Eigenschaften mit dem angegebenen Wert der Ausdruck.A property_initializer may only be given for an automatically implemented property (Automatically implemented properties), and causes the initialization of the underlying field of such properties with the value given by the expression.

Obwohl die Syntax für den Zugriff auf eine Eigenschaft, die für ein Feld übereinstimmt, wird eine Eigenschaft nicht als Variable klassifiziert.Even though the syntax for accessing a property is the same as that for a field, a property is not classified as a variable. Es ist daher nicht möglich, eine Eigenschaft als übergeben eine ref oder out Argument.Thus, it is not possible to pass a property as a ref or out argument.

Wenn eine Eigenschaftendeklaration enthält ein extern Modifizierer, die Eigenschaft gilt eine Eigenschaft "external".When a property declaration includes an extern modifier, the property is said to be an external property. Da eine Deklaration der Eigenschaft "external" keine Implementierung, jede bietet die Accessor_declarations besteht aus einem Semikolon.Because an external property declaration provides no actual implementation, each of its accessor_declarations consists of a semicolon.

Statische und EigenschaftenStatic and instance properties

Wenn eine Eigenschaftendeklaration enthält eine static Modifizierer, die Eigenschaft gilt eine statische Eigenschaft.When a property declaration includes a static modifier, the property is said to be a static property. Wenn kein static Modifizierer vorhanden ist, wird die Eigenschaft gilt eine -Instanzeigenschaft.When no static modifier is present, the property is said to be an instance property.

Eine statische Eigenschaft ist nicht mit einer bestimmten Instanz verknüpft, und es ist ein Fehler während der Kompilierung zum Verweisen auf this in den Accessoren für eine statische Eigenschaft.A static property is not associated with a specific instance, and it is a compile-time error to refer to this in the accessors of a static property.

Eine Instance-Eigenschaft ist eine bestimmte Instanz einer Klasse zugeordnet, und diese Instanz zugegriffen werden kann, als this (diesen Zugriff) in den Accessoren der Eigenschaft.An instance property is associated with a given instance of a class, and that instance can be accessed as this (This access) in the accessors of that property.

Wenn eine Eigenschaft verwiesen wird, einem Member_access (Memberzugriff) des Formulars E.M, wenn M ist eine statische Eigenschaft, E muss einen Typ mit deutenM, und wenn M ist eine Instanzeigenschaft E muss eine Instanz von einem Typ mit deuten M.When a property is referenced in a member_access (Member access) of the form E.M, if M is a static property, E must denote a type containing M, and if M is an instance property, E must denote an instance of a type containing M.

Die Unterschiede zwischen statischen und Instanzmember finden Sie weiter unten in statische und Instanzmember.The differences between static and instance members are discussed further in Static and instance members.

ZugriffsmethodenAccessors

Die Accessor_declarations Geben Sie eine Eigenschaft der ausführbaren Anweisungen lesen und Schreiben von dieser Eigenschaft zugeordnet.The accessor_declarations of a property specify the executable statements associated with reading and writing that property.

accessor_declarations
    : get_accessor_declaration set_accessor_declaration?
    | set_accessor_declaration get_accessor_declaration?
    ;

get_accessor_declaration
    : attributes? accessor_modifier? 'get' accessor_body
    ;

set_accessor_declaration
    : attributes? accessor_modifier? 'set' accessor_body
    ;

accessor_modifier
    : 'protected'
    | 'internal'
    | 'private'
    | 'protected' 'internal'
    | 'internal' 'protected'
    ;

accessor_body
    : block
    | ';'
    ;

Die Accessordeklarationen bestehen aus einer Get_accessor_declaration, Set_accessor_declaration, oder beides.The accessor declarations consist of a get_accessor_declaration, a set_accessor_declaration, or both. Jede Zugriffsmethoden-Deklaration besteht aus dem Token get oder set gefolgt von einem optionalen Accessor_modifier und Accessor_body.Each accessor declaration consists of the token get or set followed by an optional accessor_modifier and an accessor_body.

Die Verwendung von Accessor_modifiers unterliegt folgenden Einschränkungen:The use of accessor_modifiers is governed by the following restrictions:

  • Ein Accessor_modifier kann nicht in einer Schnittstelle oder in eine explizite Schnittstellenmember-Implementierung verwendet werden.An accessor_modifier may not be used in an interface or in an explicit interface member implementation.
  • Für eine Eigenschaft oder einen Indexer, der keine override Modifizierer, ein Accessor_modifier ist zulässig, nur, wenn die Eigenschaft oder der Indexer sowohl einen get und set -Accessor, und klicken Sie dann nur für eine solche darf Accessoren.For a property or indexer that has no override modifier, an accessor_modifier is permitted only if the property or indexer has both a get and set accessor, and then is permitted only on one of those accessors.
  • Für eine Eigenschaft oder einen Indexer, die enthält ein override Modifizierer, ein Accessor muss übereinstimmen. die Accessor_modifier, falls vorhanden, von der Zugriffsmethode, die überschrieben wird.For a property or indexer that includes an override modifier, an accessor must match the accessor_modifier, if any, of the accessor being overridden.
  • Die Accessor_modifier muss einen Zugriff, die streng restriktiver ist als die deklarierte Zugriffsart von Eigenschaft oder des Indexers selbst deklariert werden.The accessor_modifier must declare an accessibility that is strictly more restrictive than the declared accessibility of the property or indexer itself. Um genau zu sein:To be precise:
    • Wenn die Eigenschaft oder des Indexers eine deklarierte Zugriffsart von ist public, Accessor_modifier entweder protected internal, internal, protected, oder private.If the property or indexer has a declared accessibility of public, the accessor_modifier may be either protected internal, internal, protected, or private.
    • Wenn die Eigenschaft oder des Indexers eine deklarierte Zugriffsart von ist protected internal, Accessor_modifier entweder internal, protected, oder private.If the property or indexer has a declared accessibility of protected internal, the accessor_modifier may be either internal, protected, or private.
    • Wenn die Eigenschaft oder des Indexers eine deklarierte Zugriffsart von ist internal oder protected, Accessor_modifier muss private.If the property or indexer has a declared accessibility of internal or protected, the accessor_modifier must be private.
    • Wenn die Eigenschaft oder des Indexers eine deklarierte Zugriffsart von ist private, keine Accessor_modifier kann verwendet werden.If the property or indexer has a declared accessibility of private, no accessor_modifier may be used.

Für abstract und extern Eigenschaften, die Accessor_body für jeden Accessor angegeben einfach ein Semikolon ist.For abstract and extern properties, the accessor_body for each accessor specified is simply a semicolon. Eine nicht abstrakte, nicht Extern Eigenschaft möglicherweise jede Accessor_body können Sie ein Semikolon, in diesem Fall ist es ein automatisch implementierte Eigenschaft (automatisch implementierte Eigenschaften ).A non-abstract, non-extern property may have each accessor_body be a semicolon, in which case it is an automatically implemented property (Automatically implemented properties). Eine automatisch implementierte Eigenschaft müssen mindestens einen Get-Accessor.An automatically implemented property must have at least a get accessor. Für den Accessoren für eine andere nicht abstrakten, nicht Extern Eigenschaft die Accessor_body ist eine Block der gibt an, die Anweisungen ausgeführt werden, wenn der entsprechende-Accessor aufgerufen wird.For the accessors of any other non-abstract, non-extern property, the accessor_body is a block which specifies the statements to be executed when the corresponding accessor is invoked.

Ein get -Accessor entspricht einer Methode ohne Parameter mit einem Rückgabewert des Eigenschaftstyps.A get accessor corresponds to a parameterless method with a return value of the property type. Mit Ausnahme der als Ziel einer Zuweisung, wenn eine Eigenschaft in einem Ausdruck verwiesen wird die get -Accessor der Eigenschaft wird aufgerufen, um den Wert der Eigenschaft zu berechnen (Werte Ausdrücke).Except as the target of an assignment, when a property is referenced in an expression, the get accessor of the property is invoked to compute the value of the property (Values of expressions). Der Text, der eine get Accessor entsprechen den Regeln für die Wertrückgabe beschriebenen Methoden Methodentext.The body of a get accessor must conform to the rules for value-returning methods described in Method body. Insbesondere alle return Anweisungen im Text einer get Accessor muss einen Ausdruck implizit in den Eigenschaftentyp angeben.In particular, all return statements in the body of a get accessor must specify an expression that is implicitly convertible to the property type. Darüber hinaus den Endpunkt des eine get Accessor nicht erreicht werden kann.Furthermore, the endpoint of a get accessor must not be reachable.

Ein set Accessor entspricht einer Methode mit einem einzelnen Werteparameter des Eigenschaftstyps und void Typ zurückgeben.A set accessor corresponds to a method with a single value parameter of the property type and a void return type. Der implizite Parameter eines eine set Accessor wird stets der Name value.The implicit parameter of a set accessor is always named value. Wenn eine Eigenschaft verwiesen wird, als Ziel einer Zuweisung (Zuweisungsoperatoren), oder als Operand ++ oder -- (Postfix-Inkrement und Dekrement-Operatoren, Präfix-Inkrement und Dekrement-Operatoren), wird die set -Accessor wird aufgerufen, mit einem Argument (, deren Wert ist, die von der rechten Seite der Zuweisung oder der Operand des der ++ oder -- Operator), Gibt den neuen Wert (einfache Zuweisung).When a property is referenced as the target of an assignment (Assignment operators), or as the operand of ++ or -- (Postfix increment and decrement operators, Prefix increment and decrement operators), the set accessor is invoked with an argument (whose value is that of the right-hand side of the assignment or the operand of the ++ or -- operator) that provides the new value (Simple assignment). Der Text, der eine set Accessor entsprechen den Regeln für void beschriebenen Methoden Methodentext.The body of a set accessor must conform to the rules for void methods described in Method body. Insbesondere return Anweisungen in der set Accessor-Body sind nicht zulässig, einen Ausdruck angeben.In particular, return statements in the set accessor body are not permitted to specify an expression. Da eine set Accessor weist implizit einen Parameter namens value, es ist ein Fehler während der Kompilierung für die Deklaration einer lokalen Variable oder Konstante in einen set Accessor diesen Namen vor.Since a set accessor implicitly has a parameter named value, it is a compile-time error for a local variable or constant declaration in a set accessor to have that name.

Basierend auf das Vorhandensein oder fehlen von der get und set Accessoren, eine Eigenschaft wird wie folgt klassifiziert:Based on the presence or absence of the get and set accessors, a property is classified as follows:

  • Eine Eigenschaft, die beides umfasst eine get Accessor und einen set Accessor gilt eine Lese-/ Schreibzugriff Eigenschaft.A property that includes both a get accessor and a set accessor is said to be a read-write property.
  • Eine Eigenschaft, die nur eine get Accessor gilt eine schreibgeschützte Eigenschaft.A property that has only a get accessor is said to be a read-only property. Es ist ein Fehler während der Kompilierung für eine schreibgeschützte Eigenschaft, die das Ziel einer Zuweisung sein.It is a compile-time error for a read-only property to be the target of an assignment.
  • Eine Eigenschaft, die nur eine set Accessor gilt eine lesegeschützte Eigenschaft.A property that has only a set accessor is said to be a write-only property. Mit der Ausnahme als Ziel einer Zuweisung, es einen Fehler während der Kompilierung, um eine Nur-Schreiben-Eigenschaft in einem Ausdruck zu verweisen ist.Except as the target of an assignment, it is a compile-time error to reference a write-only property in an expression.

Im BeispielIn the example

public class Button: Control
{
    private string caption;

    public string Caption {
        get {
            return caption;
        }
        set {
            if (caption != value) {
                caption = value;
                Repaint();
            }
        }
    }

    public override void Paint(Graphics g, Rectangle r) {
        // Painting code goes here
    }
}

die Button Steuerelement deklariert ein öffentliches Caption Eigenschaft.the Button control declares a public Caption property. Die get Accessor die Caption Eigenschaft gibt die Zeichenfolge, die in der privaten gespeicherten caption Feld.The get accessor of the Caption property returns the string stored in the private caption field. Die set Accessor überprüft, ob der neue Wert unterscheidet sich von den aktuellen Wert aus, und wenn dies der Fall ist, es den neuen Wert speichert und wird neu aufgebaut, das Steuerelement.The set accessor checks if the new value is different from the current value, and if so, it stores the new value and repaints the control. Eigenschaften führen Sie oft auf das oben gezeigte Muster aus: Die get Accessor gibt einfach einen Wert, der in einem privaten Feld gespeichert und die set Accessor ändert das private Feld und führt dann zusätzlichen Aktionen erforderlich, um den Zustand des Objekts vollständig zu aktualisieren.Properties often follow the pattern shown above: The get accessor simply returns a value stored in a private field, and the set accessor modifies that private field and then performs any additional actions required to fully update the state of the object.

Erhält die Button oben gezeigte Klasse, die folgenden ist ein Beispiel mit der Caption Eigenschaft:Given the Button class above, the following is an example of use of the Caption property:

Button okButton = new Button();
okButton.Caption = "OK";            // Invokes set accessor
string s = okButton.Caption;        // Invokes get accessor

Hier ist die set -Accessor wird aufgerufen, durch das Zuweisen eines Werts der Eigenschaft und die get Accessor wird aufgerufen, indem Sie auf die Eigenschaft in einem Ausdruck verweisen.Here, the set accessor is invoked by assigning a value to the property, and the get accessor is invoked by referencing the property in an expression.

Die get und set Accessor einer Eigenschaft sind nicht unterschiedliche Elemente aus, und es ist nicht möglich, um die Accessoren der Eigenschaft separat zu deklarieren.The get and set accessors of a property are not distinct members, and it is not possible to declare the accessors of a property separately. Daher ist es nicht möglich, für die beiden Accessoren Schreib-Lese-Eigenschaft auf unterschiedlichen Zugriff haben.As such, it is not possible for the two accessors of a read-write property to have different accessibility. Im BeispielThe example

class A
{
    private string name;

    public string Name {                // Error, duplicate member name
        get { return name; }
    }

    public string Name {                // Error, duplicate member name
        set { name = value; }
    }
}

eine einzelne Lese-/ Schreibzugriff-Eigenschaft ist nicht deklariert werden.does not declare a single read-write property. Stattdessen deklariert zwei Eigenschaften mit dem gleichen Namen, eine schreibgeschützte und lesegeschützte.Rather, it declares two properties with the same name, one read-only and one write-only. Da zwei Elemente, die in der gleichen Klasse deklariert den gleichen Namen haben können, wird im Beispiel wird einen Fehler während der Kompilierung auftreten.Since two members declared in the same class cannot have the same name, the example causes a compile-time error to occur.

Wenn eine abgeleitete Klasse eine Eigenschaft mit dem gleichen Namen wie eine geerbte Eigenschaft deklariert, blendet die abgeleitete Eigenschaft die geerbte Eigenschaft in Bezug auf das Lesen und schreiben.When a derived class declares a property by the same name as an inherited property, the derived property hides the inherited property with respect to both reading and writing. Im BeispielIn the example

class A
{
    public int P {
        set {...}
    }
}

class B: A
{
    new public int P {
        get {...}
    }
}

die P -Eigenschaft in B Blendet die P -Eigenschaft in A in Bezug auf das Lesen und schreiben.the P property in B hides the P property in A with respect to both reading and writing. Daher in den AnweisungenThus, in the statements

B b = new B();
b.P = 1;          // Error, B.P is read-only
((A)b).P = 1;     // Ok, reference to A.P

die Zuweisung zu b.P verursacht einen Fehler während der Kompilierung gemeldet werden, da die schreibgeschützte P -Eigenschaft in B Blendet Sie aus, die nur-schreiben- P -Eigenschaft in A.the assignment to b.P causes a compile-time error to be reported, since the read-only P property in B hides the write-only P property in A. Beachten Sie jedoch, dass eine Umwandlung verwendet werden kann, auf die ausgeblendeten P Eigenschaft.Note, however, that a cast can be used to access the hidden P property.

Geben Sie im Gegensatz zu öffentlichen Feldern Eigenschaften eine Trennung zwischen internen Zustand eines Objekts und dessen öffentliche Schnittstelle.Unlike public fields, properties provide a separation between an object's internal state and its public interface. Betrachten Sie das Beispiel aus:Consider the example:

class Label
{
    private int x, y;
    private string caption;

    public Label(int x, int y, string caption) {
        this.x = x;
        this.y = y;
        this.caption = caption;
    }

    public int X {
        get { return x; }
    }

    public int Y {
        get { return y; }
    }

    public Point Location {
        get { return new Point(x, y); }
    }

    public string Caption {
        get { return caption; }
    }
}

Hier ist die Label -Klasse verwendet zwei int Felder x und y, um den Speicherort zu speichern.Here, the Label class uses two int fields, x and y, to store its location. Der Speicherort ist öffentlich verfügbar gemacht, als ein X und Y Eigenschaft und als eine Location Eigenschaft vom Typ Point.The location is publicly exposed both as an X and a Y property and as a Location property of type Point. Im Rahmen einer zukünftigen Version von Label, wird es einfacher, den Ort als eine Point intern für die Änderung vorgenommen werden kann, ohne Auswirkungen auf die öffentliche Schnittstelle der Klasse:If, in a future version of Label, it becomes more convenient to store the location as a Point internally, the change can be made without affecting the public interface of the class:

class Label
{
    private Point location;
    private string caption;

    public Label(int x, int y, string caption) {
        this.location = new Point(x, y);
        this.caption = caption;
    }

    public int X {
        get { return location.x; }
    }

    public int Y {
        get { return location.y; }
    }

    public Point Location {
        get { return location; }
    }

    public string Caption {
        get { return caption; }
    }
}

Hatte x und y wurde stattdessen public readonly Felder, war es unmöglich, solche eine Änderung an der Label Klasse.Had x and y instead been public readonly fields, it would have been impossible to make such a change to the Label class.

Zustand durch Eigenschaften verfügbar zu machen, ist nicht unbedingt weniger effizient als Felder direkt verfügbar zu machen.Exposing state through properties is not necessarily any less efficient than exposing fields directly. Insbesondere, wenn eine Eigenschaft nicht virtuell ist und nur eine kleine Menge an Code enthält, kann die ausführungsumgebung Aufrufe von Accessoren mit den eigentlichen Code der Accessoren ersetzen.In particular, when a property is non-virtual and contains only a small amount of code, the execution environment may replace calls to accessors with the actual code of the accessors. Dieser Prozess wird als bezeichnet inlining, und es wird der Zugriff auf Eigenschaften so effizient wie Feldzugriff, jedoch behält die höhere Flexibilität von Eigenschaften.This process is known as inlining, and it makes property access as efficient as field access, yet preserves the increased flexibility of properties.

Seit dem Aufrufen einer get Accessor Konzept entspricht dem Lesen des Werts eines Felds, gilt dies Unzulässiger Programmierstil für get Accessoren, um sichtbare Nebeneffekte haben.Since invoking a get accessor is conceptually equivalent to reading the value of a field, it is considered bad programming style for get accessors to have observable side-effects. Im BeispielIn the example

class Counter
{
    private int next;

    public int Next {
        get { return next++; }
    }
}

Der Wert des der Next Eigenschaft hängt die Anzahl der Male, die die Eigenschaft zuvor zugegriffen wurde.the value of the Next property depends on the number of times the property has previously been accessed. Klicken Sie daher Zugriff auf die Eigenschaft einen Observable Nebeneffekt erzeugt, und die Eigenschaft sollte stattdessen als eine Methode implementiert werden.Thus, accessing the property produces an observable side-effect, and the property should be implemented as a method instead.

Die "keine Nebeneffekte" Konvention für get Accessoren nicht bedeuten, dass get Accessoren sollte stets so verfasst werden einfach in Feldern gespeicherte Werte zurückgeben.The "no side-effects" convention for get accessors doesn't mean that get accessors should always be written to simply return values stored in fields. In der Tat get Accessoren häufig berechnen Sie den Wert einer Eigenschaft, indem Sie den Zugriff auf mehrere Felder oder Methoden aufrufen.Indeed, get accessors often compute the value of a property by accessing multiple fields or invoking methods. Allerdings ein ordnungsgemäß entwickeltes get Accessor führt keine Aktionen, die dazu führen, wahrnehmbare Änderungen in den Zustand des Objekts dass.However, a properly designed get accessor performs no actions that cause observable changes in the state of the object.

Eigenschaften können verwendet werden, um die Initialisierung einer Ressource bis zum Moment zu verzögern, die es erstmalig verwiesen wird.Properties can be used to delay initialization of a resource until the moment it is first referenced. Zum Beispiel:For example:

using System.IO;

public class Console
{
    private static TextReader reader;
    private static TextWriter writer;
    private static TextWriter error;

    public static TextReader In {
        get {
            if (reader == null) {
                reader = new StreamReader(Console.OpenStandardInput());
            }
            return reader;
        }
    }

    public static TextWriter Out {
        get {
            if (writer == null) {
                writer = new StreamWriter(Console.OpenStandardOutput());
            }
            return writer;
        }
    }

    public static TextWriter Error {
        get {
            if (error == null) {
                error = new StreamWriter(Console.OpenStandardError());
            }
            return error;
        }
    }
}

Die Console -Klasse enthält drei Eigenschaften In, Out, und Error, die Eingabe, Ausgabe und Fehler Geräten bzw. darstellen.The Console class contains three properties, In, Out, and Error, that represent the standard input, output, and error devices, respectively. Durch diese Member als Eigenschaften verfügbar macht, die Console Klasse kann die Initialisierung verzögert, bis sie tatsächlich verwendet werden.By exposing these members as properties, the Console class can delay their initialization until they are actually used. Beispiel: nach dem ersten Verweis auf die Out Eigenschaft, wie inFor example, upon first referencing the Out property, as in

Console.Out.WriteLine("hello, world");

die zugrunde liegende TextWriter Ausgabegerät erstellt wird.the underlying TextWriter for the output device is created. Aber wenn die Anwendung keinen Verweis auf die In und Error Eigenschaften, keine Objekte für diese Geräte erstellt werden.But if the application makes no reference to the In and Error properties, then no objects are created for those devices.

Automatisch implementierte EigenschaftenAutomatically implemented properties

Eine automatisch implementierte Eigenschaft (oder Auto-Eigenschaft kurz), ist eine nicht abstrakte nicht Extern-Eigenschaft mit dem Text von Accessoren für reine durch Semikolons.An automatically implemented property (or auto-property for short), is a non-abstract non-extern property with semicolon-only accessor bodies. Auto-Eigenschaften können müssen einen Get-Accessor und optional auch einen Set-Accessor.Auto-properties must have a get accessor and can optionally have a set accessor.

Wenn eine Eigenschaft als eine automatisch implementierte Eigenschaft angegeben wird, ein ausgeblendetes dahinter liegendes Feld wird automatisch für die Eigenschaft zur Verfügung, und die Accessoren implementiert, um Lese- und Schreibzugriff auf dieses dahinter liegende Feld.When a property is specified as an automatically implemented property, a hidden backing field is automatically available for the property, and the accessors are implemented to read from and write to that backing field. Wenn die automatische Eigenschaft keine Set-Accessor verfügt, gilt das dahinter liegende Feld readonly (schreibgeschützte Felder).If the auto-property has no set accessor, the backing field is considered readonly (Readonly fields). Genau wie ein readonly Feld eine nur-Getter-Auto-Eigenschaft kann auch zugewiesen werden im Text eines Konstruktors der einschließenden Klasse.Just like a readonly field, a getter-only auto-property can also be assigned to in the body of a constructor of the enclosing class. Eine solche Zuweisung wird direkt das Readonly dahinter liegende Feld der Eigenschaft zugewiesen.Such an assignment assigns directly to the readonly backing field of the property.

Eine Auto-Eigenschaft möglicherweise optional ein Property_initializer, das angewendet wird, direkt auf das dahinter liegende Feld als ein Variable_initializer (Variableninitialisierern) .An auto-property may optionally have a property_initializer, which is applied directly to the backing field as a variable_initializer (Variable initializers).

Im Beispiel unten geschieht Folgendes:The following example:

public class Point {
    public int X { get; set; } = 0;
    public int Y { get; set; } = 0;
}

entspricht die folgende Deklaration:is equivalent to the following declaration:

public class Point {
    private int __x = 0;
    private int __y = 0;
    public int X { get { return __x; } set { __x = value; } }
    public int Y { get { return __y; } set { __y = value; } }
}

Im Beispiel unten geschieht Folgendes:The following example:

public class ReadOnlyPoint
{
    public int X { get; }
    public int Y { get; }
    public ReadOnlyPoint(int x, int y) { X = x; Y = y; }
}

entspricht die folgende Deklaration:is equivalent to the following declaration:

public class ReadOnlyPoint
{
    private readonly int __x;
    private readonly int __y;
    public int X { get { return __x; } }
    public int Y { get { return __y; } }
    public ReadOnlyPoint(int x, int y) { __x = x; __y = y; }
}

Beachten Sie, dass die Zuweisungen für das schreibgeschützte Feld zulässig, da sie innerhalb des Konstruktors auftreten.Notice that the assignments to the readonly field are legal, because they occur within the constructor.

ZugriffAccessibility

Besitzt ein Accessor einer Accessor_modifier, die Zugriffsdomäne (Barrierefreiheit Domänen) des Accessors bestimmt ist, verwenden die deklarierte Zugriffsart von der Accessor_modifier .If an accessor has an accessor_modifier, the accessibility domain (Accessibility domains) of the accessor is determined using the declared accessibility of the accessor_modifier. Wenn ein Accessor kein Accessor_modifier, die Zugriffsdomäne des Accessors wird über die deklarierte Zugriffsart von Eigenschaft oder des Indexers bestimmt.If an accessor does not have an accessor_modifier, the accessibility domain of the accessor is determined from the declared accessibility of the property or indexer.

Das Vorhandensein einer Accessor_modifier wirkt sich nicht auf die Suche nach Membern (Operatoren) oder der überladungsauflösung (Überladungsauflösung).The presence of an accessor_modifier never affects member lookup (Operators) or overload resolution (Overload resolution). Der Modifizierer für die Eigenschaft oder der Indexer zu immer bestimmen, welche Eigenschaft oder des Indexers, unabhängig vom Kontext des Zugriffs gebunden ist.The modifiers on the property or indexer always determine which property or indexer is bound to, regardless of the context of the access.

Nachdem eine bestimmte Eigenschaft oder einen Indexer ausgewählt wurde, werden die Barrierefreiheit Domänen der beteiligten bestimmten Accessoren verwendet, um festzustellen, ob diese Nutzung gültig ist:Once a particular property or indexer has been selected, the accessibility domains of the specific accessors involved are used to determine if that usage is valid:

  • Ist die Verwendung als Wert (Werte Ausdrücke), wird die get -Accessor vorhanden und zugänglich sein muss.If the usage is as a value (Values of expressions), the get accessor must exist and be accessible.
  • Wenn die Verwendung als Ziel für eine einfache Zuweisung (einfache Zuweisung), wird die set -Accessor vorhanden und zugänglich sein muss.If the usage is as the target of a simple assignment (Simple assignment), the set accessor must exist and be accessible.
  • Wenn die Auslastung als Ziel für zusammengesetzte Zuweisung ist (Verbundzuweisung), oder als Ziel für die ++ oder -- Operatoren (Funktionsmember.9, Aufrufausdrücke), werden beide die get Accessoren und set -Accessor vorhanden und zugänglich sein muss.If the usage is as the target of compound assignment (Compound assignment), or as the target of the ++ or -- operators (Function members.9, Invocation expressions), both the get accessors and the set accessor must exist and be accessible.

Im folgenden Beispiel die Eigenschaft A.Text ist ausgeblendet, die Eigenschaft B.Text, dies gilt auch in Kontexten, in dem nur die set Accessor wird aufgerufen.In the following example, the property A.Text is hidden by the property B.Text, even in contexts where only the set accessor is called. Im Gegensatz dazu sind die Eigenschaft B.Count kann nicht zugegriffen werden, um die Klasse M, sodass die Eigenschaft zugegriffen werden kann A.Count wird stattdessen verwendet.In contrast, the property B.Count is not accessible to class M, so the accessible property A.Count is used instead.

class A
{
    public string Text {
        get { return "hello"; }
        set { }
    }

    public int Count {
        get { return 5; }
        set { }
    }
}

class B: A
{
    private string text = "goodbye"; 
    private int count = 0;

    new public string Text {
        get { return text; }
        protected set { text = value; }
    }

    new protected int Count { 
        get { return count; }
        set { count = value; }
    }
}

class M
{
    static void Main() {
        B b = new B();
        b.Count = 12;             // Calls A.Count set accessor
        int i = b.Count;          // Calls A.Count get accessor
        b.Text = "howdy";         // Error, B.Text set accessor not accessible
        string s = b.Text;        // Calls B.Text get accessor
    }
}

Ein Accessor, der verwendet wird, um eine Schnittstelle implementieren, möglicherweise kein Accessor_modifier.An accessor that is used to implement an interface may not have an accessor_modifier. Wenn nur ein Accessor verwendet wird, eine Schnittstelle implementieren, kann der andere Accessor deklariert werden, mit einem Accessor_modifier:If only one accessor is used to implement an interface, the other accessor may be declared with an accessor_modifier:

public interface I
{
    string Prop { get; }
}

public class C: I
{
    public Prop {
        get { return "April"; }       // Must not have a modifier here
        internal set {...}            // Ok, because I.Prop has no set accessor
    }
}

Virtuelle, versiegelt, überschriebene und abstrakte eigenschaftenzugriffsmethodenVirtual, sealed, override, and abstract property accessors

Ein virtual -Eigenschaftendeklaration gibt an, dass die Accessoren der Eigenschaft virtuell sind.A virtual property declaration specifies that the accessors of the property are virtual. Die virtual Modifizierer gilt für beide Accessoren der Schreib-Lese-Eigenschaft – es ist nicht möglich, dass nur ein Accessor einer Eigenschaft Lese-/ Schreibzugriff auf nicht virtuell sein.The virtual modifier applies to both accessors of a read-write property—it is not possible for only one accessor of a read-write property to be virtual.

Ein abstract Eigenschaftendeklaration gibt an, dass die Accessoren der Eigenschaft sind virtuell, jedoch bietet keine tatsächliche Implementierung der Accessoren.An abstract property declaration specifies that the accessors of the property are virtual, but does not provide an actual implementation of the accessors. Stattdessen müssen nicht abstrakte abgeleitete Klassen ihre eigene Implementierung für die Accessoren durch Überschreiben der Eigenschaft bereitstellen.Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the property. Da Sie ein Accessor für eine abstrakte Eigenschaftendeklaration keine Implementierungen, bietet die Accessor_body besteht einfach aus einem Semikolon.Because an accessor for an abstract property declaration provides no actual implementation, its accessor_body simply consists of a semicolon.

Eine Eigenschaftendeklaration, die beide enthält die abstract und override Modifizierer gibt an, dass die Eigenschaft ist abstrakt und überschreibt eine Basiseigenschaft.A property declaration that includes both the abstract and override modifiers specifies that the property is abstract and overrides a base property. Accessoren für diese Eigenschaft ist auch abstrakt sind.The accessors of such a property are also abstract.

Abstrakte Eigenschaftendeklarationen sind nur in abstrakten Klassen zulässig (abstrakte Klassen). Die Zugriffsmethoden einer geerbten virtuellen-Eigenschaft können in einer abgeleiteten Klasse überschrieben werden, durch eine Eigenschaftendeklaration, der angibt, ein override Richtlinie.Abstract property declarations are only permitted in abstract classes (Abstract classes).The accessors of an inherited virtual property can be overridden in a derived class by including a property declaration that specifies an override directive. Dies bezeichnet man als ein überschreiben Eigenschaftendeklaration.This is known as an overriding property declaration. Eine überschreibende Eigenschaftsdeklaration ist eine neue Eigenschaft nicht deklarieren.An overriding property declaration does not declare a new property. Stattdessen ist einfach die Implementierungen der Accessoren einer vorhandenen virtuellen Eigenschaft spezialisiert.Instead, it simply specializes the implementations of the accessors of an existing virtual property.

Eine überschreibende Eigenschaftsdeklaration muss genau gleichen Zugriffsmodifizierer, Typ und Namen als die geerbte Eigenschaft angeben.An overriding property declaration must specify the exact same accessibility modifiers, type, and name as the inherited property. Wenn die geerbte Eigenschaft hat nur einen einzelnen Accessor (d. h., wenn die geerbte Eigenschaft schreibgeschützt oder lesegeschützt ist), das die überschreibende Eigenschaft muss nur diesen Accessor enthalten.If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property must include only that accessor. Wenn die geerbte Eigenschaft enthält beide Accessoren (d. h., wenn die geerbte Eigenschaft Lese-/ Schreibzugriff ist), die überschreibende Eigenschaft kann entweder eines einzelnen Accessors oder beide Accessoren enthalten.If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors.

Eine überschreibende Eigenschaftsdeklaration herausgeberkontos ausgewiesenen Form der sealed Modifizierer.An overriding property declaration may include the sealed modifier. Verwendung dieser Modifizierer wird verhindert, dass eine abgeleitete Klasse weiter Überschreiben der Eigenschaft.Use of this modifier prevents a derived class from further overriding the property. Die Zugriffsmethoden einer versiegelten Eigenschaft sind ebenfalls versiegelt.The accessors of a sealed property are also sealed.

Verhalten Syntax, virtuellen, "sealed" außer Kraft setzen und abstrakten Accessor genau wie virtuelle, "sealed" Override "und" abstrakte Methoden, mit Ausnahme der Unterschiede in der Deklarations- und Aufrufsyntax.Except for differences in declaration and invocation syntax, virtual, sealed, override, and abstract accessors behave exactly like virtual, sealed, override and abstract methods. Insbesondere die Regeln, die in beschriebenen virtuelle Methoden, Methoden außer Kraft setzen, Versiegelte Methoden, und abstrakten Methoden gelten wie Accessoren wurden die Methoden der entsprechenden:Specifically, the rules described in Virtual methods, Override methods, Sealed methods, and Abstract methods apply as if accessors were methods of a corresponding form:

  • Ein get -Accessor entspricht einer Methode ohne Parameter mit einem Rückgabewert von den Eigenschaftentyp und den gleichen Modifizierer wie die Eigenschaft.A get accessor corresponds to a parameterless method with a return value of the property type and the same modifiers as the containing property.
  • Ein set Accessor entspricht einer Methode mit einem Einzelwert-Parameter, der den Typ der Eigenschaft, ein void Typ und die gleichen Modifizierer wie die Eigenschaft zurück.A set accessor corresponds to a method with a single value parameter of the property type, a void return type, and the same modifiers as the containing property.

Im BeispielIn the example

abstract class A
{
    int y;

    public virtual int X {
        get { return 0; }
    }

    public virtual int Y {
        get { return y; }
        set { y = value; }
    }

    public abstract int Z { get; set; }
}

X ist eine virtuelle nur-Lese Eigenschaft, Y ist eine virtuelle Lese-/ Schreibzugriff-Eigenschaft, und Z ist eine abstrakte Eigenschaft mit Lese-/ Schreibzugriff.X is a virtual read-only property, Y is a virtual read-write property, and Z is an abstract read-write property. Da Z ist eine abstrakte Methode der enthaltenden Klasse A muss auch als abstrakt deklariert werden.Because Z is abstract, the containing class A must also be declared abstract.

Eine abgeleitete Klasse A wird unten gezeigt:A class that derives from A is show below:

class B: A
{
    int z;

    public override int X {
        get { return base.X + 1; }
    }

    public override int Y {
        set { base.Y = value < 0? 0: value; }
    }

    public override int Z {
        get { return z; }
        set { z = value; }
    }
}

Hier wird die Deklarationen der X, Y, und Z Eigenschaftendeklarationen überschreiben.Here, the declarations of X, Y, and Z are overriding property declarations. Jede Eigenschaftendeklaration entspricht genau der Zugriffsmodifizierer, Typ und Namen der entsprechenden geerbte Eigenschaften.Each property declaration exactly matches the accessibility modifiers, type, and name of the corresponding inherited property. Die get Accessor X und set Accessor Y verwenden die base Schlüsselwort, um die geerbten Accessoren.The get accessor of X and the set accessor of Y use the base keyword to access the inherited accessors. Die Deklaration von Z beide Accessoren abstrakte überschreibungen – es gibt also keine ausstehenden abstrakte Funktionsmember in B, und B ist zulässig, eine nicht abstrakte Klasse sein.The declaration of Z overrides both abstract accessors—thus, there are no outstanding abstract function members in B, and B is permitted to be a non-abstract class.

Wenn eine Eigenschaft deklariert ist, als ein override, alle überschriebenen Accessoren müssen für den überschreibenden Code zugänglich sein.When a property is declared as an override, any overridden accessors must be accessible to the overriding code. Darüber hinaus muss die deklarierte Zugriffsart von sowohl die Eigenschaft oder den Indexer und Accessoren, mit dem überschriebenen Member und den Accessoren übereinstimmen.In addition, the declared accessibility of both the property or indexer itself, and of the accessors, must match that of the overridden member and accessors. Zum Beispiel:For example:

public class B
{
    public virtual int P {
        protected set {...}
        get {...}
    }
}

public class D: B
{
    public override int P {
        protected set {...}            // Must specify protected here
        get {...}                      // Must not have a modifier here
    }
}

EreignisseEvents

Ein Ereignis ist ein Element, das ein Objekt oder eine Klasse, um Benachrichtigungen zu senden zu können.An event is a member that enables an object or class to provide notifications. Clients können ausführbaren Code für Ereignisse anfügen, indem Sie die Angabe Ereignishandler.Clients can attach executable code for events by supplying event handlers.

Ereignisse werden mit deklariert Event_declarations:Events are declared using event_declarations:

event_declaration
    : attributes? event_modifier* 'event' type variable_declarators ';'
    | attributes? event_modifier* 'event' type member_name '{' event_accessor_declarations '}'
    ;

event_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | event_modifier_unsafe
    ;

event_accessor_declarations
    : add_accessor_declaration remove_accessor_declaration
    | remove_accessor_declaration add_accessor_declaration
    ;

add_accessor_declaration
    : attributes? 'add' block
    ;

remove_accessor_declaration
    : attributes? 'remove' block
    ;

Ein Event_declaration eventuell einen Satz von Attribute (Attribute) und eine gültige Kombination der vier Zugriffsmodifizierer (Zugriffsmodifizierer ), wird die new (der new-Modifizierer), static (statische und Instanzmethoden), virtual (virtuelle Methoden), override (Methoden außer Kraft setzen), sealed (Versiegelte Methoden), abstract (abstrakten Methoden), und extern (Externe Methoden) Modifizierer.An event_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), static (Static and instance methods), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

Ereignisdeklarationen gelten dieselben Regeln wie Methodendeklarationen (Methoden) im Hinblick auf die gültigen Kombinationen der Modifizierer.Event declarations are subject to the same rules as method declarations (Methods) with regard to valid combinations of modifiers.

Die Typ eines Ereignisses muss die Deklaration einer Delegate_type (Verweistypen), und dass Delegate_type muss mindestens als wie das Ereignis selbst zugegriffen werden kann (Barrierefreiheit Einschränkungen).The type of an event declaration must be a delegate_type (Reference types), and that delegate_type must be at least as accessible as the event itself (Accessibility constraints).

Eine Ereignisdeklaration herausgeberkontos ausgewiesenen Form Event_accessor_declarations.An event declaration may include event_accessor_declarations. Jedoch wenn, für nicht-Extern, nicht abstrakte Ereignisse nicht der Compiler sie automatisch bereitgestellt (Feldähnliche Ereignisse); für "extern"-Ereignisse, die Accessoren extern bereitgestellt werden.However, if it does not, for non-extern, non-abstract events, the compiler supplies them automatically (Field-like events); for extern events, the accessors are provided externally.

Ein Event-Deklaration, die ausgelassen Event_accessor_declarations definiert eine oder mehrere Ereignisse – eine für jede der Variable_declarators.An event declaration that omits event_accessor_declarations defines one or more events—one for each of the variable_declarators. Die Attribute und Modifizierer, gelten für alle Member deklariert, indem z. B. eine Event_declaration.The attributes and modifiers apply to all of the members declared by such an event_declaration.

Es ist ein Fehler während der Kompilierung für eine Event_declaration zu beiden enthalten die abstract Modifizierer und geschweifte Klammern getrennter Event_accessor_declarations.It is a compile-time error for an event_declaration to include both the abstract modifier and brace-delimited event_accessor_declarations.

Wenn eine Ereignisdeklaration enthält ein extern Modifizierer verwenden, das Ereignis wird als ein externes Ereignis.When an event declaration includes an extern modifier, the event is said to be an external event. Da eine externes Ereignisdeklaration keine tatsächliche Implementierung bereitstellt, ist ein Fehler für sie zu beiden enthalten die extern Modifizierer und Event_accessor_declarations.Because an external event declaration provides no actual implementation, it is an error for it to include both the extern modifier and event_accessor_declarations.

Es ist ein Fehler während der Kompilierung für eine Variable_declarator einer Event-Deklaration mit einer abstract oder external Modifizierer enthalten eine Variable_initializer.It is a compile-time error for a variable_declarator of an event declaration with an abstract or external modifier to include a variable_initializer.

Ein Ereignis kann verwendet werden, wie der linke Operand der += und -= Operatoren (Ereignis Zuweisung).An event can be used as the left-hand operand of the += and -= operators (Event assignment). Diese Operatoren werden, bzw. zum Anfügen von Ereignishandlern zu oder Entfernen von-Ereignishandler von einem Ereignis, und der Zugriffsmodifizierer des Ereignisses steuern die Kontexte, in denen solche Vorgänge zulässig sind.These operators are used, respectively, to attach event handlers to or to remove event handlers from an event, and the access modifiers of the event control the contexts in which such operations are permitted.

Da += und -= sind die einzigen Operationen, die auf ein Ereignis außerhalb des Typs, der deklariert zulässig sind, das Ereignis, den externen Code können hinzufügen und entfernen-Handler für ein Ereignis, jedoch kann nicht auf andere Weise zu erhalten oder ändern die zugrunde liegenden Liste des Ereignisses Handler.Since += and -= are the only operations that are permitted on an event outside the type that declares the event, external code can add and remove handlers for an event, but cannot in any other way obtain or modify the underlying list of event handlers.

In einem Vorgang des Formulars x += y oder x -= yWenn x ist ein Ereignis aus, und der Verweis erfolgt außerhalb des Typs, die die Deklaration enthält x, weist das Ergebnis des Vorgangs den Typ void (im Gegensatz zur Verwendung Der Typ des x, mit dem Wert des x nach der Zuweisung).In an operation of the form x += y or x -= y, when x is an event and the reference takes place outside the type that contains the declaration of x, the result of the operation has type void (as opposed to having the type of x, with the value of x after the assignment). Mit dieser Regel wird verhindert, dass externen Code indirekt überprüft den zugrunde liegenden Delegaten eines Ereignisses.This rule prohibits external code from indirectly examining the underlying delegate of an event.

Das folgende Beispiel zeigt, wie Ereignishandler angefügt werden, um Instanzen von der Button Klasse:The following example shows how event handlers are attached to instances of the Button class:

public delegate void EventHandler(object sender, EventArgs e);

public class Button: Control
{
    public event EventHandler Click;
}

public class LoginDialog: Form
{
    Button OkButton;
    Button CancelButton;

    public LoginDialog() {
        OkButton = new Button(...);
        OkButton.Click += new EventHandler(OkButtonClick);
        CancelButton = new Button(...);
        CancelButton.Click += new EventHandler(CancelButtonClick);
    }

    void OkButtonClick(object sender, EventArgs e) {
        // Handle OkButton.Click event
    }

    void CancelButtonClick(object sender, EventArgs e) {
        // Handle CancelButton.Click event
    }
}

Hier die LoginDialog Instanzkonstruktor erstellt zwei Button Instanzen und fügt der Ereignishandler die Click Ereignisse.Here, the LoginDialog instance constructor creates two Button instances and attaches event handlers to the Click events.

Feldähnliche EreignisseField-like events

In den Programmtext der Klasse oder Struktur, die die Deklaration eines Ereignisses enthält, können bestimmte Ereignisse wie Felder verwendet werden.Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. Auf diese Weise verwendet werden soll, ein Ereignis darf nicht sein abstract oder extern, und müssen nicht explizit Event_accessor_declarations.To be used in this way, an event must not be abstract or extern, and must not explicitly include event_accessor_declarations. Derartiges Ereignis kann in jedem Kontext verwendet werden, die ein Feld zulässt.Such an event can be used in any context that permits a field. Das Feld enthält einen Delegaten (Delegaten) die bezieht sich auf die Liste der Ereignishandler, die das Ereignis hinzugefügt wurden.The field contains a delegate (Delegates) which refers to the list of event handlers that have been added to the event. Wenn keine Ereignishandler hinzugefügt wurden, enthält das Feld null.If no event handlers have been added, the field contains null.

Im BeispielIn the example

public delegate void EventHandler(object sender, EventArgs e);

public class Button: Control
{
    public event EventHandler Click;

    protected void OnClick(EventArgs e) {
        if (Click != null) Click(this, e);
    }

    public void Reset() {
        Click = null;
    }
}

Click Dient als ein Feld innerhalb der Button Klasse.Click is used as a field within the Button class. Wie im Beispiel wird veranschaulicht, kann das Feld werden überprüft, geändert und in den Delegaten aufrufen von Ausdrücken verwendet.As the example demonstrates, the field can be examined, modified, and used in delegate invocation expressions. Die OnClick -Methode in der die Button "löst" die Click Ereignis.The OnClick method in the Button class "raises" the Click event. Das Auslösen eines Ereignisses entspricht exakt dem Aufrufen des Delegaten, der durch das Ereignis repräsentiert wird, es gibt deshalb keine besonderen Sprachkonstrukte zum Auslösen von Ereignissen.The notion of raising an event is precisely equivalent to invoking the delegate represented by the event—thus, there are no special language constructs for raising events. Beachten Sie, dass der Delegataufruf eine Überprüfung vorangestellt ist, die sicherstellt, dass der Delegat ungleich Null ist.Note that the delegate invocation is preceded by a check that ensures the delegate is non-null.

Außerhalb der Variablendeklaration der Button -Klasse, die Click Member kann nur verwendet werden, auf der linken Seite von der += und -= Operatoren, wie inOutside the declaration of the Button class, the Click member can only be used on the left-hand side of the += and -= operators, as in

b.Click += new EventHandler(...);

Ein Delegat der Aufrufliste von fügt die Click Ereignis undwhich appends a delegate to the invocation list of the Click event, and

b.Click -= new EventHandler(...);

das einen Delegaten aus der Aufrufliste entfernt die Click Ereignis.which removes a delegate from the invocation list of the Click event.

Beim Kompilieren ein feldähnliches Ereignis der Compiler erstellt automatisch Speicher zum Speichern von Delegaten, und Zugriffsmethoden für das Ereignis, die hinzufügen oder Entfernen von Ereignishandlern auf das Delegatfeld erstellt.When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field. Die Vorgänge hinzufügen und entfernen sind threadsicher, und möglicherweise (jedoch nicht erforderlich, um) Fertig Zeit belegen die Sperre (die Lock-Anweisung) auf das enthaltende Objekt für ein Instanzereignis oder die Typ-Objekt (anonym Objektausdrücke Erstellung) für ein statisches Ereignis.The addition and removal operations are thread safe, and may (but are not required to) be done while holding the lock (The lock statement) on the containing object for an instance event, or the type object (Anonymous object creation expressions) for a static event.

Daher eine Instanzereignisdeklaration des Formulars:Thus, an instance event declaration of the form:

class X
{
    public event D Ev;
}

wird in etwa gleich kompiliert werden:will be compiled to something equivalent to:

class X
{
    private D __Ev;  // field to hold the delegate

    public event D Ev {
        add {
            /* add the delegate in a thread safe way */
        }

        remove {
            /* remove the delegate in a thread safe way */
        }
    }
}

In der Klasse X, Verweise auf Ev auf der linken Seite von der += und -= Operatoren dazu führen, dass das Hinzufügen und remove-Accessoren besitzen, die aufgerufen werden.Within the class X, references to Ev on the left-hand side of the += and -= operators cause the add and remove accessors to be invoked. Alle anderen Verweise auf Ev werden kompiliert, um das ausgeblendete Feld verweisen __Ev stattdessen (Memberzugriff).All other references to Ev are compiled to reference the hidden field __Ev instead (Member access). Der Name "__Ev" ist ein beliebiger; das ausgeblendete Feld möglicherweise eine beliebige oder gar kein Name überhaupt.The name "__Ev" is arbitrary; the hidden field could have any name or no name at all.

EreignisaccessorenEvent accessors

Ereignisdeklarationen in der Regel auslassen Event_accessor_declarations, z. B. die Button Beispiel oben.Event declarations typically omit event_accessor_declarations, as in the Button example above. Eine Situation dafür umfasst also den Fall, in dem die Speicherkosten, die ein Feld pro Ereignis nicht zulässig ist.One situation for doing so involves the case in which the storage cost of one field per event is not acceptable. In solchen Fällen kann eine Klasse enthalten Event_accessor_declarations und einen privaten Mechanismus zum Speichern der Liste der Ereignishandler verwenden.In such cases, a class can include event_accessor_declarations and use a private mechanism for storing the list of event handlers.

Die Event_accessor_declarations eines Ereignisses Geben Sie die ausführbare Anweisungen, die mit dem Hinzufügen und Entfernen von Ereignishandlern verknüpft ist.The event_accessor_declarations of an event specify the executable statements associated with adding and removing event handlers.

Die Accessordeklarationen bestehen aus einer Add_accessor_declaration und Remove_accessor_declaration.The accessor declarations consist of an add_accessor_declaration and a remove_accessor_declaration. Jede Zugriffsmethoden-Deklaration besteht aus dem Token add oder remove gefolgt von einem Block.Each accessor declaration consists of the token add or remove followed by a block. Die Block zugeordneten ein Add_accessor_declaration gibt an, die Anweisungen, die ausgeführt werden, wenn ein Ereignishandler hinzugefügt wird, und die Block eine zugeordnetRemove_accessor_declaration gibt an, die Anweisungen, die ausgeführt werden, wenn ein Ereignishandler entfernt wird.The block associated with an add_accessor_declaration specifies the statements to execute when an event handler is added, and the block associated with a remove_accessor_declaration specifies the statements to execute when an event handler is removed.

Jede Add_accessor_declaration und Remove_accessor_declaration entspricht einer Methode mit einem einzelnen Werteparameter des Ereignistyps und void Typ zurückgeben.Each add_accessor_declaration and remove_accessor_declaration corresponds to a method with a single value parameter of the event type and a void return type. Den Namen der impliziten Parameters mit der ein Ereignisaccessor value.The implicit parameter of an event accessor is named value. Wenn ein Ereignis in einer Ereignis-Zuweisung verwendet wird, wird der entsprechende Ereignisaccessor verwendet.When an event is used in an event assignment, the appropriate event accessor is used. Insbesondere ist der Zuweisungsoperator += der Add-Accessor verwendet wird, und wenn der Zuweisungsoperator -= der Remove-Accessor verwendet wird.Specifically, if the assignment operator is += then the add accessor is used, and if the assignment operator is -= then the remove accessor is used. In beiden Fällen wird der Rechte Operand des Zuweisungsoperators als Argument für den Ereignisaccessor verwendet.In either case, the right-hand operand of the assignment operator is used as the argument to the event accessor. Der Block eine Add_accessor_declaration oder Remove_accessor_declaration entsprechen den Regeln für void beschriebenen Methoden Methodentext.The block of an add_accessor_declaration or a remove_accessor_declaration must conform to the rules for void methods described in Method body. Insbesondere return Anweisungen in einem solchen Block sind nicht zulässig, einen Ausdruck angeben.In particular, return statements in such a block are not permitted to specify an expression.

Da ein Ereignisaccessor implizit einen Parameter namens weist value, es ist ein Fehler während der Kompilierung für eine lokale Variable oder Konstante in einem Ereignisaccessor auf diesen Namen nicht bereits deklariert.Since an event accessor implicitly has a parameter named value, it is a compile-time error for a local variable or constant declared in an event accessor to have that name.

Im BeispielIn the example

class Control: Component
{
    // Unique keys for events
    static readonly object mouseDownEventKey = new object();
    static readonly object mouseUpEventKey = new object();

    // Return event handler associated with key
    protected Delegate GetEventHandler(object key) {...}

    // Add event handler associated with key
    protected void AddEventHandler(object key, Delegate handler) {...}

    // Remove event handler associated with key
    protected void RemoveEventHandler(object key, Delegate handler) {...}

    // MouseDown event
    public event MouseEventHandler MouseDown {
        add { AddEventHandler(mouseDownEventKey, value); }
        remove { RemoveEventHandler(mouseDownEventKey, value); }
    }

    // MouseUp event
    public event MouseEventHandler MouseUp {
        add { AddEventHandler(mouseUpEventKey, value); }
        remove { RemoveEventHandler(mouseUpEventKey, value); }
    }

    // Invoke the MouseUp event
    protected void OnMouseUp(MouseEventArgs args) {
        MouseEventHandler handler; 
        handler = (MouseEventHandler)GetEventHandler(mouseUpEventKey);
        if (handler != null)
            handler(this, args);
    }
}

die Control -Klasse implementiert einen internen Speichermechanismus für Ereignisse.the Control class implements an internal storage mechanism for events. Die AddEventHandler Methode ordnet einen Delegatwert mit einem Schlüssel, der GetEventHandler Methodenrückgabe der Delegat, der derzeit mit einem Schlüssel zugeordnet sind und die RemoveEventHandler Methode entfernt einen Delegaten als Ereignishandler für das angegebene Ereignis.The AddEventHandler method associates a delegate value with a key, the GetEventHandler method returns the delegate currently associated with a key, and the RemoveEventHandler method removes a delegate as an event handler for the specified event. Es empfiehlt sich, der zugrunde liegenden Speichermechanismus ist so entworfen, dass es keine Kosten für das Zuordnen fallen einer null delegieren Wert mit einem Schlüssel und somit Ereignisse ohne Behandlung keinen Speicher nutzen.Presumably, the underlying storage mechanism is designed such that there is no cost for associating a null delegate value with a key, and thus unhandled events consume no storage.

Statische und EreignisseStatic and instance events

Wenn eine Ereignisdeklaration enthält eine static Modifizierer verwenden, das Ereignis gilt eine statisches Ereignis.When an event declaration includes a static modifier, the event is said to be a static event. Wenn kein static Modifizierer vorhanden ist, wird das Ereignis wird als ein Instanzereignisses.When no static modifier is present, the event is said to be an instance event.

Ein statisches Ereignis ist nicht mit einer bestimmten Instanz verknüpft, und es ist ein Fehler während der Kompilierung zum Verweisen auf this in den Accessoren für ein statisches Ereignis.A static event is not associated with a specific instance, and it is a compile-time error to refer to this in the accessors of a static event.

Ein Instanzereignis eine bestimmte Instanz einer Klasse zugeordnet ist, und diese Instanz zugegriffen werden kann, als this (diesen Zugriff) in den Zugriffsmethoden des Ereignisses.An instance event is associated with a given instance of a class, and this instance can be accessed as this (This access) in the accessors of that event.

Wenn ein Ereignis verwiesen wird, einem Member_access (Memberzugriff) des Formulars E.M, wenn M ist ein statisches Ereignis, E muss einen Typ mit deutenM, und wenn M ist ein Instanzereignis E muss eine Instanz von einem Typ mit deuten M.When an event is referenced in a member_access (Member access) of the form E.M, if M is a static event, E must denote a type containing M, and if M is an instance event, E must denote an instance of a type containing M.

Die Unterschiede zwischen statischen und Instanzmember finden Sie weiter unten in statische und Instanzmember.The differences between static and instance members are discussed further in Static and instance members.

Virtuelle, versiegelt, überschriebene und abstrakte ereigniszugriffsmethodenVirtual, sealed, override, and abstract event accessors

Ein virtual gibt an, dass die Accessoren dieses Ereignisses virtuell sind.A virtual event declaration specifies that the accessors of that event are virtual. Die virtual Modifizierer gilt für beide Accessoren eines Ereignisses.The virtual modifier applies to both accessors of an event.

Ein abstract Ereignisdeklaration gibt an, dass die Accessoren des Ereignisses sind virtuell, jedoch bietet keine tatsächliche Implementierung der Accessoren.An abstract event declaration specifies that the accessors of the event are virtual, but does not provide an actual implementation of the accessors. Stattdessen müssen nicht abstrakte abgeleitete Klassen ihre eigene Implementierung für die Accessoren angeben, durch Überschreiben des Ereignisses.Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the event. Da eine abstrakte Ereignisdeklaration keine tatsächliche Implementierung bereitstellt, kann keine es bereitstellen, geschweifte Klammern getrennter Event_accessor_declarations.Because an abstract event declaration provides no actual implementation, it cannot provide brace-delimited event_accessor_declarations.

Eine Ereignisdeklaration, das beide enthält die abstract und override Modifizierer gibt an, dass das Ereignis ist abstrakt und überschreibt eine grundlegende-Ereignis.An event declaration that includes both the abstract and override modifiers specifies that the event is abstract and overrides a base event. Die Accessoren eines solchen Ereignisses sind auch abstrakt.The accessors of such an event are also abstract.

Abstraktes Ereignis-Deklarationen sind nur in abstrakten Klassen zulässig (abstrakte Klassen).Abstract event declarations are only permitted in abstract classes (Abstract classes).

Die zugriffmethoden von einer geerbten virtuellen Veranstaltung können in einer abgeleiteten Klasse überschrieben werden, durch eine Ereignisdeklaration, der angibt, einschließlich einer override Modifizierer.The accessors of an inherited virtual event can be overridden in a derived class by including an event declaration that specifies an override modifier. Dies bezeichnet man als ein überschreiben Ereignisdeklaration.This is known as an overriding event declaration. Eine überschreibende Ereignisdeklaration wird ein neues Ereignis nicht deklarieren.An overriding event declaration does not declare a new event. Stattdessen ist einfach die Implementierungen der Accessoren für ein vorhandenes virtuelles Ereignis spezialisiert.Instead, it simply specializes the implementations of the accessors of an existing virtual event.

Eine überschreibende Ereignisdeklaration muss dem genau gleichen Zugriffsmodifizierer, Typ und Namen als das außer Kraft gesetzte Ereignis angeben.An overriding event declaration must specify the exact same accessibility modifiers, type, and name as the overridden event.

Eine überschreibende Event-Deklaration enthalten möglicherweise die sealed Modifizierer.An overriding event declaration may include the sealed modifier. Verwendung dieser Modifizierer wird verhindert, dass eine abgeleitete Klasse weiter Überschreiben des Ereignisses.Use of this modifier prevents a derived class from further overriding the event. Die Accessoren der versiegelten Ereignisses sind ebenfalls versiegelt.The accessors of a sealed event are also sealed.

Es ist ein Fehler während der Kompilierung für eine überschreibende Ereignisdeklaration sollen eine new Modifizierer.It is a compile-time error for an overriding event declaration to include a new modifier.

Verhalten Syntax, virtuellen, "sealed" außer Kraft setzen und abstrakten Accessor genau wie virtuelle, "sealed" Override "und" abstrakte Methoden, mit Ausnahme der Unterschiede in der Deklarations- und Aufrufsyntax.Except for differences in declaration and invocation syntax, virtual, sealed, override, and abstract accessors behave exactly like virtual, sealed, override and abstract methods. Insbesondere die Regeln, die in beschriebenen virtuelle Methoden, Methoden außer Kraft setzen, Versiegelte Methoden, und abstrakten Methoden gelten wie Accessoren wurden die Methoden der entsprechenden.Specifically, the rules described in Virtual methods, Override methods, Sealed methods, and Abstract methods apply as if accessors were methods of a corresponding form. Jeder Accessor entspricht einer Methode mit einem Einzelwert-Parameter, der den Ereignistyp vorgesehen, eine void Typ und die gleichen Modifizierer wie das enthaltende Ereignis zurück.Each accessor corresponds to a method with a single value parameter of the event type, a void return type, and the same modifiers as the containing event.

IndexerIndexers

Ein Indexer ist ein Element, das ein Objekt, auf die gleiche Weise wie ein Array indiziert werden kann.An indexer is a member that enables an object to be indexed in the same way as an array. Indexer sind mit deklariert Indexer_declarations:Indexers are declared using indexer_declarations:

indexer_declaration
    : attributes? indexer_modifier* indexer_declarator indexer_body
    ;

indexer_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | indexer_modifier_unsafe
    ;

indexer_declarator
    : type 'this' '[' formal_parameter_list ']'
    | type interface_type '.' 'this' '[' formal_parameter_list ']'
    ;

indexer_body
    : '{' accessor_declarations '}' 
    | '=>' expression ';'
    ;

Ein Indexer_declaration eventuell einen Satz von Attribute (Attribute) und eine gültige Kombination der vier Zugriffsmodifizierer (Zugriffsmodifizierer ), wird die new (der new-Modifizierer), virtual (virtuelle Methoden), override (Methoden außer Kraft setzen ), sealed (Versiegelte Methoden), abstract (abstrakten Methoden), und extern (externe Methoden) Modifizierer.An indexer_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

Indexerdeklarationen sind, gelten dieselben Regeln wie Methodendeklarationen (Methoden) im Hinblick auf die gültigen Kombinationen von Modifizierern, mit der eine Ausnahme, die den static-Modifizierer darf nicht auf eine Indexerdeklaration.Indexer declarations are subject to the same rules as method declarations (Methods) with regard to valid combinations of modifiers, with the one exception being that the static modifier is not permitted on an indexer declaration.

Die Modifizierer virtual, override, und abstract gegenseitig außer in einem Fall.The modifiers virtual, override, and abstract are mutually exclusive except in one case. Die abstract und override Modifizierer können zusammen verwendet werden, sodass abstrakte Indexer einen virtuellen überschreiben kann.The abstract and override modifiers may be used together so that an abstract indexer can override a virtual one.

Die Typ Deklaration gibt den Typ des Elements des Indexers, der durch die Deklaration eines Indexers an.The type of an indexer declaration specifies the element type of the indexer introduced by the declaration. Wenn der Indexer eine explizite Schnittstellenmember-Implementierung, ist die Typ folgt das Schlüsselwort this.Unless the indexer is an explicit interface member implementation, the type is followed by the keyword this. Für eine explizite Schnittstellenmember-Implementierung die Typ gefolgt von einer Interface_type, eine ".", und das Schlüsselwort this.For an explicit interface member implementation, the type is followed by an interface_type, a ".", and the keyword this. Im Gegensatz zu anderen Membern haben Indexer keine benutzerdefinierten Namen.Unlike other members, indexers do not have user-defined names.

Die Formal_parameter_list gibt die Parameter des Indexers.The formal_parameter_list specifies the parameters of the indexer. Die Liste der formalen Parameter eines Indexers entspricht einer Methode (Methodenparameter), mit dem Unterschied, dass mindestens ein Parameter angegeben werden muss, und dass die ref und out Parametermodifizierern sind nicht zulässig. .The formal parameter list of an indexer corresponds to that of a method (Method parameters), except that at least one parameter must be specified, and that the ref and out parameter modifiers are not permitted.

Die Typ einen Indexer und alle Typen verwiesen wird, der Formal_parameter_list muss mindestens dieselben zugriffsmöglichkeiten bieten wie der Indexer selbst (Barrierefreiheit Einschränkungen).The type of an indexer and each of the types referenced in the formal_parameter_list must be at least as accessible as the indexer itself (Accessibility constraints).

Ein Indexer_body entweder besteht möglicherweise aus einem Accessor-Body oder ausdruckskörper.An indexer_body may either consist of an accessor body or an expression body. In einem Accessortext Accessor_declarations, die eingeschlossen werden müssen, "{"und"}" Token, deklarieren die Accessoren (Accessoren) der Eigenschaft.In an accessor body, accessor_declarations, which must be enclosed in "{" and "}" tokens, declare the accessors (Accessors) of the property. Die Accessoren angeben, die ausführbaren Anweisungen lesen und schreiben die Eigenschaft zugeordnet wird.The accessors specify the executable statements associated with reading and writing the property.

Ein ausdruckskörper bestehend aus "=>" gefolgt von einem Ausdruck E und ein Semikolon entspricht genau der Anweisungstext { get { return E; } }, und kann daher nur verwendet werden nur-Getter-Indexer angeben, wo ist das Ergebnis der getter-Methode durch einen einzelnen Ausdruck angegeben.An expression body consisting of "=>" followed by an expression E and a semicolon is exactly equivalent to the statement body { get { return E; } }, and can therefore only be used to specify getter-only indexers where the result of the getter is given by a single expression.

Obwohl die Syntax für den Zugriff auf eine Indexer-Element identisch, die für ein Arrayelement ist, wird eine Indexer-Element nicht als Variable klassifiziert.Even though the syntax for accessing an indexer element is the same as that for an array element, an indexer element is not classified as a variable. Folglich ist es nicht möglich, übergeben einen Indexer-Element als ein ref oder out Argument.Thus, it is not possible to pass an indexer element as a ref or out argument.

Die Liste der formalen Parameter eines Indexers definiert die Signatur (Signaturen und überladen) des Indexers.The formal parameter list of an indexer defines the signature (Signatures and overloading) of the indexer. Die Signatur eines Indexers besteht insbesondere die Anzahl und Typen der formalen Parameter.Specifically, the signature of an indexer consists of the number and types of its formal parameters. Der Elementtyp und den Namen der formalen Parameter sind nicht Teil der Signatur eines Indexers.The element type and names of the formal parameters are not part of an indexer's signature.

Die Signatur eines Indexers muss die Signaturen aller anderen in derselben Klasse deklarierten Indexer unterscheiden.The signature of an indexer must differ from the signatures of all other indexers declared in the same class.

Indexer und Eigenschaften sind konzeptionell sehr ähnlich, unterscheiden sich jedoch auf folgende Weise:Indexers and properties are very similar in concept, but differ in the following ways:

  • Eine Eigenschaft wird mit seinem Namen identifiziert, während von der Signatur ein Indexers identifiziert wird.A property is identified by its name, whereas an indexer is identified by its signature.
  • Eine Eigenschaft erfolgt über eine Simple_name (einfache Namen) oder ein Member_access (Memberzugriff), während eines Indexers Element erfolgt über eine Element_access (Indexerzugriff).A property is accessed through a simple_name (Simple names) or a member_access (Member access), whereas an indexer element is accessed through an element_access (Indexer access).
  • Eine Eigenschaft kann sein, eine static Member, während ein Indexers immer ein Instanzmember ist.A property can be a static member, whereas an indexer is always an instance member.
  • Ein get Accessor einer Eigenschaft entspricht einer Methode ohne Parameter, während eine get Accessor eines Indexers entspricht einer Methode mit dem dieselbe Liste formaler Parameter wie der Indexer.A get accessor of a property corresponds to a method with no parameters, whereas a get accessor of an indexer corresponds to a method with the same formal parameter list as the indexer.
  • Ein set Accessor einer Eigenschaft entspricht einer Methode mit einem einzigen Parameter, die mit dem Namen value, während eine set Accessor eines Indexers entspricht einer Methode mit dem dieselbe Liste formaler Parameter wie der Indexer sowie einen zusätzlichen Parameter mit dem Namen value.A set accessor of a property corresponds to a method with a single parameter named value, whereas a set accessor of an indexer corresponds to a method with the same formal parameter list as the indexer, plus an additional parameter named value.
  • Es ist ein Fehler während der Kompilierung für einen Indexeraccessor für eine lokale Variable mit dem gleichen Namen wie ein Indexerparameter zu deklarieren.It is a compile-time error for an indexer accessor to declare a local variable with the same name as an indexer parameter.
  • In eine überschreibende Eigenschaftsdeklaration die geerbte Eigenschaft erfolgt mithilfe der Syntax base.P, wobei P ist der Eigenschaftenname.In an overriding property declaration, the inherited property is accessed using the syntax base.P, where P is the property name. In der Indexerdeklaration einer überschreibenden der geerbte Indexer erfolgt mithilfe der Syntax base[E], wobei E ist eine durch Trennzeichen getrennte Liste von Ausdrücken.In an overriding indexer declaration, the inherited indexer is accessed using the syntax base[E], where E is a comma separated list of expressions.
  • Es gibt kein Konzept für "automatisch implementierte Indexer".There is no concept of an "automatically implemented indexer". Es ist ein Fehler auf einen nicht abstrakten, nicht extern-Indexer mit Semikolon-Accessoren aufweisen.It is an error to have a non-abstract, non-external indexer with semicolon accessors.

Abgesehen von diesen unterschieden werden alle Regeln in definierten Accessoren und automatisch implementierten Eigenschaften als auch für Eigenschaftenaccessoren angewendet.Aside from these differences, all rules defined in Accessors and Automatically implemented properties apply to indexer accessors as well as to property accessors.

Wenn eine Indexerdeklaration enthält ein extern Modifizierer, der Indexer gilt eine externe Indexer.When an indexer declaration includes an extern modifier, the indexer is said to be an external indexer. Da eine externe Indexerdeklaration keine Implementierung, jede bietet die Accessor_declarations besteht aus einem Semikolon.Because an external indexer declaration provides no actual implementation, each of its accessor_declarations consists of a semicolon.

Das folgende Beispiel deklariert eine BitArray -Klasse, die einen Indexer für den Zugriff auf den einzelnen Bits im BitArray implementiert.The example below declares a BitArray class that implements an indexer for accessing the individual bits in the bit array.

using System;

class BitArray
{
    int[] bits;
    int length;

    public BitArray(int length) {
        if (length < 0) throw new ArgumentException();
        bits = new int[((length - 1) >> 5) + 1];
        this.length = length;
    }

    public int Length {
        get { return length; }
    }

    public bool this[int index] {
        get {
            if (index < 0 || index >= length) {
                throw new IndexOutOfRangeException();
            }
            return (bits[index >> 5] & 1 << index) != 0;
        }
        set {
            if (index < 0 || index >= length) {
                throw new IndexOutOfRangeException();
            }
            if (value) {
                bits[index >> 5] |= 1 << index;
            }
            else {
                bits[index >> 5] &= ~(1 << index);
            }
        }
    }
}

Einer Instanz von der BitArray Klasse erheblich weniger Arbeitsspeicher belegt als eine entsprechende bool[] (da jeder Wert der ersten nur ein Bit anstelle von belegt Letzteres des ein Byte), aber es ermöglicht die gleichen Vorgänge wie eine bool[].An instance of the BitArray class consumes substantially less memory than a corresponding bool[] (since each value of the former occupies only one bit instead of the latter's one byte), but it permits the same operations as a bool[].

Die folgenden CountPrimes -Klasse verwendet ein BitArray und den klassischen "Sieb"-Algorithmus berechnet die Anzahl der Primzahlen wie folgt zwischen 1 und eine festgelegte maximale:The following CountPrimes class uses a BitArray and the classical "sieve" algorithm to compute the number of primes between 1 and a given maximum:

class CountPrimes
{
    static int Count(int max) {
        BitArray flags = new BitArray(max + 1);
        int count = 1;
        for (int i = 2; i <= max; i++) {
            if (!flags[i]) {
                for (int j = i * 2; j <= max; j += i) flags[j] = true;
                count++;
            }
        }
        return count;
    }

    static void Main(string[] args) {
        int max = int.Parse(args[0]);
        int count = Count(max);
        Console.WriteLine("Found {0} primes between 1 and {1}", count, max);
    }
}

Beachten Sie, dass die Syntax für den Zugriff auf Elemente der BitArray ist genau dieselbe wie für eine bool[].Note that the syntax for accessing elements of the BitArray is precisely the same as for a bool[].

Das folgende Beispiel zeigt eine Raster mit 26 * 10-Klasse, die einen Indexer mit zwei Parametern verfügt.The following example shows a 26 * 10 grid class that has an indexer with two parameters. Der erste Parameter ist erforderlich, um ein Groß- oder Kleinbuchstaben im Bereich von A bis Z sein, und die zweite ist erforderlich, um eine ganze Zahl im Bereich von 0 bis 9 sein.The first parameter is required to be an upper- or lowercase letter in the range A-Z, and the second is required to be an integer in the range 0-9.

using System;

class Grid
{
    const int NumRows = 26;
    const int NumCols = 10;

    int[,] cells = new int[NumRows, NumCols];

    public int this[char c, int col] {
        get {
            c = Char.ToUpper(c);
            if (c < 'A' || c > 'Z') {
                throw new ArgumentException();
            }
            if (col < 0 || col >= NumCols) {
                throw new IndexOutOfRangeException();
            }
            return cells[c - 'A', col];
        }

        set {
            c = Char.ToUpper(c);
            if (c < 'A' || c > 'Z') {
                throw new ArgumentException();
            }
            if (col < 0 || col >= NumCols) {
                throw new IndexOutOfRangeException();
            }
            cells[c - 'A', col] = value;
        }
    }
}

Indexer überladenIndexer overloading

Die Regeln der überladungsauflösung Indexer werden im beschrieben Typrückschluss.The indexer overload resolution rules are described in Type inference.

OperatorenOperators

Ein Operator ist ein Member, die Bedeutung eines Operators Ausdruck definiert, die auf Instanzen der Klasse angewendet werden können.An operator is a member that defines the meaning of an expression operator that can be applied to instances of the class. Operatoren werden mit deklariert Operator_declarations:Operators are declared using operator_declarations:

operator_declaration
    : attributes? operator_modifier+ operator_declarator operator_body
    ;

operator_modifier
    : 'public'
    | 'static'
    | 'extern'
    | operator_modifier_unsafe
    ;

operator_declarator
    : unary_operator_declarator
    | binary_operator_declarator
    | conversion_operator_declarator
    ;

unary_operator_declarator
    : type 'operator' overloadable_unary_operator '(' type identifier ')'
    ;

overloadable_unary_operator
    : '+' | '-' | '!' | '~' | '++' | '--' | 'true' | 'false'
    ;

binary_operator_declarator
    : type 'operator' overloadable_binary_operator '(' type identifier ',' type identifier ')'
    ;

overloadable_binary_operator
    : '+'   | '-'   | '*'   | '/'   | '%'   | '&'   | '|'   | '^'   | '<<'
    | right_shift | '=='  | '!='  | '>'   | '<'   | '>='  | '<='
    ;

conversion_operator_declarator
    : 'implicit' 'operator' type '(' type identifier ')'
    | 'explicit' 'operator' type '(' type identifier ')'
    ;

operator_body
    : block
    | '=>' expression ';'
    | ';'
    ;

Es gibt drei Kategorien von Überladbare Operatoren: Unäre Operatoren (unäre Operatoren), binäre Operatoren (binären Operatoren), und Konvertierungsoperatoren (Konvertierungsoperatoren).There are three categories of overloadable operators: Unary operators (Unary operators), binary operators (Binary operators), and conversion operators (Conversion operators).

Die Operator_body ist entweder ein Semikolon, ein Anweisungstext oder ausdruckskörper.The operator_body is either a semicolon, a statement body or an expression body. Eine-Anweisungstext besteht aus einem Block, die angibt, dass die Anweisungen, die ausgeführt werden, wenn der Operator aufgerufen wird.A statement body consists of a block, which specifies the statements to execute when the operator is invoked. Die Block entsprechen den Regeln für die Wertrückgabe beschriebenen Methoden Methodentext.The block must conform to the rules for value-returning methods described in Method body. Ein ausdruckskörper besteht aus => gefolgt von einem Ausdruck und ein Semikolon, und gibt einen einzelnen Ausdruck ausführen, wenn der Operator aufgerufen wird.An expression body consists of => followed by an expression and a semicolon, and denotes a single expression to perform when the operator is invoked.

Für extern Operatoren, die Operator_body besteht einfach aus einem Semikolon.For extern operators, the operator_body consists simply of a semicolon. Für alle anderen Operatoren wird die Operator_body ist ein Blocktext oder einen ausdruckskörper.For all other operators, the operator_body is either a block body or an expression body.

Die folgenden Regeln gelten für alle Operatordeklarationen:The following rules apply to all operator declarations:

  • Eine Operatordeklaration muss enthalten beide eine public und static Modifizierer.An operator declaration must include both a public and a static modifier.
  • Die Parameter eines Operators muss den-Parameter (-Wertparameter).The parameter(s) of an operator must be value parameters (Value parameters). Es ist ein Fehler während der Kompilierung für eine Operatordeklaration an ref oder out Parameter.It is a compile-time error for an operator declaration to specify ref or out parameters.
  • Die Signatur eines Operators (unäre Operatoren, binären Operatoren, Konvertierungsoperatoren) muss sich von den Signaturen aller anderen Operatoren, die im deklarierten unterscheiden die derselben Klasse.The signature of an operator (Unary operators, Binary operators, Conversion operators) must differ from the signatures of all other operators declared in the same class.
  • Alle Typen, die auf die verwiesen wird in der Operatordeklaration eines müssen mindestens dieselben zugriffsmöglichkeiten bieten wie der Operator selbst sein (Barrierefreiheit Einschränkungen).All types referenced in an operator declaration must be at least as accessible as the operator itself (Accessibility constraints).
  • Es ist ein Fehler für den gleichen Modifizierer für mehrere Male in einem Operatordeklaration angezeigt werden.It is an error for the same modifier to appear multiple times in an operator declaration.

Jeder Operatorkategorie schränkt, wie in den folgenden Abschnitten beschrieben.Each operator category imposes additional restrictions, as described in the following sections.

Wie andere Member werden die Operatoren, die in einer Basisklasse von abgeleiteten Klassen geerbt.Like other members, operators declared in a base class are inherited by derived classes. Da Operatordeklarationen immer erforderlich, die Klasse oder Struktur, die in der der Operator, zur Teilnahme an der Signatur des Operators deklariert wird, ist es nicht möglich, für einen Operator in einer abgeleiteten Klasse deklariert, um einen Operator in einer Basisklasse deklariert auszublenden.Because operator declarations always require the class or struct in which the operator is declared to participate in the signature of the operator, it is not possible for an operator declared in a derived class to hide an operator declared in a base class. Daher die new Modifizierer ist nicht erforderlich, und daher nicht zulässig, in der Operatordeklaration eines.Thus, the new modifier is never required, and therefore never permitted, in an operator declaration.

Weitere Informationen zur unären und binären Operatoren finden Sie im Operatoren.Additional information on unary and binary operators can be found in Operators.

Weitere Informationen zu Konvertierungsoperatoren befinden sich benutzerdefinierte Konvertierungen.Additional information on conversion operators can be found in User-defined conversions.

Unäre OperatorenUnary operators

Die folgenden Regeln gelten für unären Operator-Deklarationen, wobei T bezeichnet den Instanztyp der Klasse oder Struktur, die sich die Operatordeklaration enthält:The following rules apply to unary operator declarations, where T denotes the instance type of the class or struct that contains the operator declaration:

  • Ein unäres +, -, !, oder ~ Operator muss einen einzelnen Parameter vom Typ akzeptieren T oder T? und können jeden Typ zurückgeben.A unary +, -, !, or ~ operator must take a single parameter of type T or T? and can return any type.
  • Ein unäres ++ oder -- Operator muss einen einzelnen Parameter vom Typ akzeptieren T oder T? und denselben Typ oder einen davon Typ abgeleiteten zurückgeben müssen.A unary ++ or -- operator must take a single parameter of type T or T? and must return that same type or a type derived from it.
  • Ein unäres true oder false Operator muss einen einzelnen Parameter vom Typ akzeptieren T oder T? und müssen Rückgabetyp bool.A unary true or false operator must take a single parameter of type T or T? and must return type bool.

Die Signatur eines unären Operators besteht aus den Operatortoken (+, -, !, ~, ++, --, true, oder false) und den Typ des den einzelnen formalen Parameter.The signature of a unary operator consists of the operator token (+, -, !, ~, ++, --, true, or false) and the type of the single formal parameter. Der Rückgabetyp ist nicht Teil der Signatur für einen unäroperator, noch ist der Name des formalen Parameters.The return type is not part of a unary operator's signature, nor is the name of the formal parameter.

Die true und false unäre Operatoren müssen paarweise Deklaration.The true and false unary operators require pair-wise declaration. Ein Fehler während der Kompilierung tritt auf, wenn eine Klasse einer dieser Operatoren deklariert, ohne auch die andere zu deklarieren.A compile-time error occurs if a class declares one of these operators without also declaring the other. Die true und false Operatoren werden ausführlich in bedingten logischen Operatoren eine benutzerdefinierte und boolesche Ausdrücke.The true and false operators are described further in User-defined conditional logical operators and Boolean expressions.

Das folgende Beispiel zeigt eine Implementierung und die anschließende Verwendung von operator ++ für eine ganze Zahl Vector-Klasse:The following example shows an implementation and subsequent usage of operator ++ for an integer vector class:

public class IntVector
{
    public IntVector(int length) {...}

    public int Length {...}                 // read-only property

    public int this[int index] {...}        // read-write indexer

    public static IntVector operator ++(IntVector iv) {
        IntVector temp = new IntVector(iv.Length);
        for (int i = 0; i < iv.Length; i++)
            temp[i] = iv[i] + 1;
        return temp;
    }
}

class Test
{
    static void Main() {
        IntVector iv1 = new IntVector(4);    // vector of 4 x 0
        IntVector iv2;

        iv2 = iv1++;    // iv2 contains 4 x 0, iv1 contains 4 x 1
        iv2 = ++iv1;    // iv2 contains 4 x 2, iv1 contains 4 x 2
    }
}

Beachten Sie, wie der Operator den Wert 1 mit dem Operanden, wie das Postfixinkrement zu addieren erzeugten Methodenrückgabe und Dekrement-Operatoren (Postfix-Inkrement und Dekrement-Operatoren), und die Präfix-Inkrement und Dekrement Operatoren (Präfix-Inkrement und Dekrement-Operatoren).Note how the operator method returns the value produced by adding 1 to the operand, just like the postfix increment and decrement operators (Postfix increment and decrement operators), and the prefix increment and decrement operators (Prefix increment and decrement operators). Im Gegensatz zu muss in C++ wird diese Methode nicht den Wert des Operanden direkt ändern.Unlike in C++, this method need not modify the value of its operand directly. Ändern den Wert des Operanden würde in der Tat die Standardsemantik des Postfixinkrement-Operators verletzt werden.In fact, modifying the operand value would violate the standard semantics of the postfix increment operator.

Binäre OperatorenBinary operators

Die folgenden Regeln gelten für binären Operator-Deklarationen, wobei T bezeichnet den Instanztyp der Klasse oder Struktur, die sich die Operatordeklaration enthält:The following rules apply to binary operator declarations, where T denotes the instance type of the class or struct that contains the operator declaration:

  • Ein binärer nicht Shift-Operator muss zwei Parameter, die mindestens eine der Typ aufweisen einen muss annehmen T oder T?, und Sie können jeden Typ zurückgeben.A binary non-shift operator must take two parameters, at least one of which must have type T or T?, and can return any type.
  • Ein binäres << oder >> -Operator muss zwei Parameter, die das erste Argument Typ aufweisen einen muss annehmen T oder T? und dem zweiten muss einen Typ aufweisen int oder int?, und Sie können jeden Typ zurückgeben.A binary << or >> operator must take two parameters, the first of which must have type T or T? and the second of which must have type int or int?, and can return any type.

Die Signatur eines binären Operators besteht aus den Operatortoken (+, -, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=, oder <=) und die Typen der formalen Parameter zwei.The signature of a binary operator consists of the operator token (+, -, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=, or <=) and the types of the two formal parameters. Der Rückgabetyp und die Namen der formalen Parameter sind nicht Teil eines binären Operators-Signatur.The return type and the names of the formal parameters are not part of a binary operator's signature.

Bestimmte binären Operatoren müssen paarweise Deklaration.Certain binary operators require pair-wise declaration. Für jede Deklaration entweder ein paar-Operators muss eine entsprechende Deklaration des anderen Operators des Paars vorhanden sein.For every declaration of either operator of a pair, there must be a matching declaration of the other operator of the pair. Zwei Operatordeklarationen Abgleich aus, wenn sie den gleichen Rückgabetyp und den gleichen Typ für jeden Parameter aufweisen.Two operator declarations match when they have the same return type and the same type for each parameter. Die folgenden Operatoren müssen paarweise Deklaration:The following operators require pair-wise declaration:

  • operator == und operator !=operator == and operator !=
  • operator > und operator <operator > and operator <
  • operator >= und operator <=operator >= and operator <=

KonvertierungsoperatorenConversion operators

Eine Konvertierung Operator-Deklaration führt eine benutzerdefinierte Konvertierung (benutzerdefinierte Konvertierungen) das Standardfehlerprotokoll erweitert, der vordefinierten impliziten und expliziten Konvertierungen.A conversion operator declaration introduces a user-defined conversion (User-defined conversions) which augments the pre-defined implicit and explicit conversions.

Eine Konvertierung Operator-Deklaration, enthält die implicit -Schlüsselwort Führt eine implizite Konvertierung von benutzerdefinierten.A conversion operator declaration that includes the implicit keyword introduces a user-defined implicit conversion. Implizite Konvertierungen können in einer Vielzahl von Situationen, wie z.B. Memberaufrufen für die Funktion Cast-Ausdrücke und Zuweisungen auftreten.Implicit conversions can occur in a variety of situations, including function member invocations, cast expressions, and assignments. Dies wird weiter in implizite Konvertierungen.This is described further in Implicit conversions.

Eine Konvertierung Operator-Deklaration, enthält die explicit -Schlüsselwort Führt eine benutzerdefinierte explizite Konvertierung.A conversion operator declaration that includes the explicit keyword introduces a user-defined explicit conversion. Explizite Konvertierungen können in der Cast-Ausdrücke auftreten, und werden ausführlich in explizite Konvertierungen.Explicit conversions can occur in cast expressions, and are described further in Explicit conversions.

Ein Konvertierungsoperator konvertiert aus einer Datenquelle, die von der Parametertyp des Konvertierungsoperators in einen Zieltyp, angegeben durch den Rückgabetyp der Operator für die Konvertierung angegeben.A conversion operator converts from a source type, indicated by the parameter type of the conversion operator, to a target type, indicated by the return type of the conversion operator.

Für einen bestimmten Quell- S und einen Zieltyp T, wenn S oder T werden auf NULL festlegbare Typen können S0 und T0 finden Sie in die zugrunde liegende Typen, andernfalls S0 und T0 sind gleich S und T bzw.For a given source type S and target type T, if S or T are nullable types, let S0 and T0 refer to their underlying types, otherwise S0 and T0 are equal to S and T respectively. Eine Klasse oder Struktur ist zulässig, deklarieren Sie eine Konvertierung aus einer Datenquelle S in einen Zieltyp T nur dann, wenn alle der folgenden Bedingungen erfüllt sind:A class or struct is permitted to declare a conversion from a source type S to a target type T only if all of the following are true:

  • S0 und T0 gibt verschiedene Typen.S0 and T0 are different types.
  • Entweder S0 oder T0 ist der Typ Klasse oder Struktur, die in der die Operatordeklaration erfolgt.Either S0 or T0 is the class or struct type in which the operator declaration takes place.
  • Weder S0 noch T0 ist ein Interface_type.Neither S0 nor T0 is an interface_type.
  • Mit Ausnahme von benutzerdefinierten Konvertierungen, eine Konvertierung ist nicht vom S zu T oder T zu S.Excluding user-defined conversions, a conversion does not exist from S to T or from T to S.

Im Rahmen dieser Regeln werden alle zugeordneten Parameter geben S oder T gelten als eindeutige Typen, die keine vererbungsbeziehung mit anderen Typen, und alle Einschränkungen für diesen Typ mit dem Parameter werden ignoriert.For the purposes of these rules, any type parameters associated with S or T are considered to be unique types that have no inheritance relationship with other types, and any constraints on those type parameters are ignored.

Im BeispielIn the example

class C<T> {...}

class D<T>: C<T>
{
    public static implicit operator C<int>(D<T> value) {...}      // Ok
    public static implicit operator C<string>(D<T> value) {...}   // Ok
    public static implicit operator C<T>(D<T> value) {...}        // Error
}

die ersten zwei Operatordeklarationen sind zulässig, da für die Zwecke Indexer.3 und T und int und string gelten jeweils eindeutige Typen ohne Beziehung.the first two operator declarations are permitted because, for the purposes of Indexers.3, T and int and string respectively are considered unique types with no relationship. Der dritte Operator ist jedoch ein Fehler, da C<T> ist die Basisklasse der D<T>.However, the third operator is an error because C<T> is the base class of D<T>.

Ein Konvertierungsoperator muss aus der zweiten Regel ergibt sich, dass konvertieren, auf ein oder von der Klasse oder Struktur-Typ, in dem der Operator deklariert ist.From the second rule it follows that a conversion operator must convert either to or from the class or struct type in which the operator is declared. Beispielsweise ist es möglich, dass eine Klasse oder Struktur-Typ C definieren Sie eine Konvertierung von C zu int und int zu C, jedoch nicht von int zu bool.For example, it is possible for a class or struct type C to define a conversion from C to int and from int to C, but not from int to bool.

Es ist nicht möglich, um eine vordefinierte Konvertierung direkt neu zu definieren.It is not possible to directly redefine a pre-defined conversion. Konvertierungsoperatoren sind daher nicht zulässig, Konvertieren von oder zu object Da implizite und explizite Konvertierungen zwischen bereits vorhanden sind object und alle anderen Typen.Thus, conversion operators are not allowed to convert from or to object because implicit and explicit conversions already exist between object and all other types. Ebenso können weder Quelle noch die Zieltypen einer Konvertierung sein, ein Basistyp des anderen, da eine Konvertierung, klicken Sie dann noch vorhanden wäre.Likewise, neither the source nor the target types of a conversion can be a base type of the other, since a conversion would then already exist.

Allerdings ist es möglich, die Operatoren in generischen Typen deklarieren, die bei bestimmten Typargumenten, geben Sie als vordefinierte Konvertierungen Konvertierungen, die bereits vorhanden.However, it is possible to declare operators on generic types that, for particular type arguments, specify conversions that already exist as pre-defined conversions. Im BeispielIn the example

struct Convertible<T>
{
    public static implicit operator Convertible<T>(T value) {...}
    public static explicit operator T(Convertible<T> value) {...}
}

Geben Sie bei object angegeben ist, als Typargument für T, der zweite Operator deklariert eine Konvertierung, die bereits vorhanden ist (eine implizite, und daher auch eine explizite Konvertierung von jedem Typ vorhanden ist object).when type object is specified as a type argument for T, the second operator declares a conversion that already exists (an implicit, and therefore also an explicit, conversion exists from any type to type object).

In Fällen, in dem eine vordefinierte Konvertierung zwischen zwei Typen vorhanden ist, werden keine benutzerdefinierten Konvertierungen zwischen diesen Typen ignoriert.In cases where a pre-defined conversion exists between two types, any user-defined conversions between those types are ignored. Dies gilt insbesondere in folgenden Fällen:Specifically:

  • Wenn eine vordefinierte implizite Konvertierung (implizite Konvertierungen) vom Typ S eingeben T, alle benutzerdefinierten Konvertierungen (implizit oder explizit) von S zu T werden ignoriert.If a pre-defined implicit conversion (Implicit conversions) exists from type S to type T, all user-defined conversions (implicit or explicit) from S to T are ignored.
  • Wenn die vordefinierten explizite Konvertierung (explizite Konvertierungen) vom Typ S eingeben T, eine benutzerdefinierte, explizite Konvertierung von S zu T werden ignoriert.If a pre-defined explicit conversion (Explicit conversions) exists from type S to type T, any user-defined explicit conversions from S to T are ignored. Darüber hinaus:Furthermore:

Wenn T ist ein Schnittstellentyp, der den benutzerdefinierten impliziten Konvertierungen von S zu T werden ignoriert.If T is an interface type, user-defined implicit conversions from S to T are ignored.

Andernfalls, eine benutzerdefinierte impliziten Konvertierungen von S zu T gelten weiterhin.Otherwise, user-defined implicit conversions from S to T are still considered.

Für alle Typen jedoch object, die Operatoren deklariert, indem die Convertible<T> oben genannten Typ nicht in Konflikt mit vordefinierten Konvertierungen.For all types but object, the operators declared by the Convertible<T> type above do not conflict with pre-defined conversions. Zum Beispiel:For example:

void F(int i, Convertible<int> n) {
    i = n;                          // Error
    i = (int)n;                     // User-defined explicit conversion
    n = i;                          // User-defined implicit conversion
    n = (Convertible<int>)i;        // User-defined implicit conversion
}

Für den Typ jedoch object, vordefinierte Konvertierungen ausblenden, die eine benutzerdefinierte Konvertierungen in allen Fällen jedoch eine:However, for type object, pre-defined conversions hide the user-defined conversions in all cases but one:

void F(object o, Convertible<object> n) {
    o = n;                         // Pre-defined boxing conversion
    o = (object)n;                 // Pre-defined boxing conversion
    n = o;                         // User-defined implicit conversion
    n = (Convertible<object>)o;    // Pre-defined unboxing conversion
}

Benutzerdefinierte Konvertierungen sind nicht zulässig, Konvertieren von oder zu Interface_types.User-defined conversions are not allowed to convert from or to interface_types. Insbesondere diese Beschränkung wird sichergestellt, dass keine benutzerdefinierten Transformationen erfolgen, bei der Konvertierung in eine Interface_type, und dass eine Konvertierung in eine Interface_type nur erfolgreich, wenn das Objekt konvertierte tatsächlich implementiert den angegebenen Interface_type.In particular, this restriction ensures that no user-defined transformations occur when converting to an interface_type, and that a conversion to an interface_type succeeds only if the object being converted actually implements the specified interface_type.

Die Signatur eines Konvertierungsoperators besteht aus den Quelltyp und der Zieltyp.The signature of a conversion operator consists of the source type and the target type. (Beachten Sie, dass dies die einzige Form des Elements ist der Rückgabetyp für die in der Signatur beteiligt ist.) Die implicit oder explicit Klassifizierung eines Konvertierungsoperators ist nicht Teil der Signatur des Operators.(Note that this is the only form of member for which the return type participates in the signature.) The implicit or explicit classification of a conversion operator is not part of the operator's signature. Daher eine Klasse oder Struktur kann nicht deklariert sowohl eine implicit und explicit Konvertierungsoperator mit den gleichen Typen von Quelle und Ziel.Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types.

Im Allgemeinen sollten implizite Konvertierungen benutzerdefinierte entworfen werden, keine Ausnahmen auslösen und keine Informationen verlieren.In general, user-defined implicit conversions should be designed to never throw exceptions and never lose information. Wenn eine benutzerdefinierte Konvertierung Anstieg auf Ausnahmen erhalten (z. B. weil das Quellargument außerhalb des gültigen Bereichs ist) oder Verlust von Informationen (z. B. das höherwertige Bits werden verworfen), und klicken Sie dann auf diese Konvertierung als eine explizite Konvertierung definiert werden sollte.If a user-defined conversion can give rise to exceptions (for example, because the source argument is out of range) or loss of information (such as discarding high-order bits), then that conversion should be defined as an explicit conversion.

Im BeispielIn the example

using System;

public struct Digit
{
    byte value;

    public Digit(byte value) {
        if (value < 0 || value > 9) throw new ArgumentException();
        this.value = value;
    }

    public static implicit operator byte(Digit d) {
        return d.value;
    }

    public static explicit operator Digit(byte b) {
        return new Digit(b);
    }
}

die Konvertierung von Digit zu byte ist implizit, da sie nie Ausnahmen auslöst oder Informationen, aber die Konvertierung von verliert byte zu Digit ist seit explizit Digit können nur eine Teilmenge der möglichen darstellen Werte von einem byte.the conversion from Digit to byte is implicit because it never throws exceptions or loses information, but the conversion from byte to Digit is explicit since Digit can only represent a subset of the possible values of a byte.

InstanzkonstruktorenInstance constructors

Ein Instanzkonstruktor ist ein Member, der die erforderlichen Aktionen zum Initialisieren einer Instanz einer Klasse implementiert.An instance constructor is a member that implements the actions required to initialize an instance of a class. Instanzkonstruktoren werden mit deklariert Constructor_declarations:Instance constructors are declared using constructor_declarations:

constructor_declaration
    : attributes? constructor_modifier* constructor_declarator constructor_body
    ;

constructor_modifier
    : 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'extern'
    | constructor_modifier_unsafe
    ;

constructor_declarator
    : identifier '(' formal_parameter_list? ')' constructor_initializer?
    ;

constructor_initializer
    : ':' 'base' '(' argument_list? ')'
    | ':' 'this' '(' argument_list? ')'
    ;

constructor_body
    : block
    | ';'
    ;

Ein Constructor_declaration eventuell einen Satz von Attribute (Attribute), eine gültige Kombination der vier Zugriffsmodifizierer (Zugriffsmodifizierer ), und ein extern (externe Methoden) Modifizierer.A constructor_declaration may include a set of attributes (Attributes), a valid combination of the four access modifiers (Access modifiers), and an extern (External methods) modifier. Eine Konstruktordeklaration verwendet darf nicht den gleichen Modifizierer mehrfach enthalten.A constructor declaration is not permitted to include the same modifier multiple times.

Die Bezeichner von einem Constructor_declarator müssen den Namen der Klasse, die in der die Instanzkonstruktor deklariert wird.The identifier of a constructor_declarator must name the class in which the instance constructor is declared. Wenn ein anderen Namen angegeben wird, tritt ein Fehler während der Kompilierung.If any other name is specified, a compile-time error occurs.

Der optionale Formal_parameter_list einer Instanz unterliegt Konstruktor dieselben Regeln wie für die Formal_parameter_list einer Methode (Methoden).The optional formal_parameter_list of an instance constructor is subject to the same rules as the formal_parameter_list of a method (Methods). Liste der formalen Parameter definiert die Signatur (Signaturen und überladen) eines Instanzkonstruktors und steuert den Prozess, bei dem der überladungsauflösung (Typrückschluss) Wählt eine bestimmte Bei einem Aufruf Instance-Konstruktor.The formal parameter list defines the signature (Signatures and overloading) of an instance constructor and governs the process whereby overload resolution (Type inference) selects a particular instance constructor in an invocation.

Alle Typen verwiesen wird, der Formal_parameter_list einer Instanz-Konstruktor muss mindestens dieselben zugriffsmöglichkeiten bieten wie der Konstruktor selbst sein (Barrierefreiheit Einschränkungen).Each of the types referenced in the formal_parameter_list of an instance constructor must be at least as accessible as the constructor itself (Accessibility constraints).

Der optionale Constructor_initializer gibt an, eine andere Instanzkonstruktor aufrufen, die vor dem Ausführen der Anweisungen, die im angegebenen die Constructor_body dieses Konstruktors Instanz.The optional constructor_initializer specifies another instance constructor to invoke before executing the statements given in the constructor_body of this instance constructor. Dies wird weiter in Konstruktorinitialisierer.This is described further in Constructor initializers.

Wenn eine Konstruktordeklaration verwendet enthält ein extern Modifizierer, der Konstruktor wird als ein externer Konstruktor.When a constructor declaration includes an extern modifier, the constructor is said to be an external constructor. Da eine externe Konstruktordeklaration keine Implementierungen, bietet die Constructor_body besteht aus einem Semikolon.Because an external constructor declaration provides no actual implementation, its constructor_body consists of a semicolon. Für alle übrigen Konstruktoren die Constructor_body besteht aus einem Block der gibt an, die Anweisungen, um eine neue Instanz der Klasse zu initialisieren.For all other constructors, the constructor_body consists of a block which specifies the statements to initialize a new instance of the class. Dies entspricht genau dem der Block einer Instanzmethode mit einem void Rückgabetyp (Methodentext).This corresponds exactly to the block of an instance method with a void return type (Method body).

Instanzkonstruktoren werden nicht geerbt.Instance constructors are not inherited. Daher verfügt eine Klasse keine Instanzkonstruktoren auf als die tatsächlich in der Klasse deklariert wurden.Thus, a class has no instance constructors other than those actually declared in the class. Wenn eine Klasse keine Instanz-Deklarationen enthält, wird ein Standardkonstruktor für die Instanz wird automatisch bereitgestellt (Standardkonstruktoren).If a class contains no instance constructor declarations, a default instance constructor is automatically provided (Default constructors).

Instanzkonstruktoren werden aufgerufen, indem Object_creation_expressions (Erstellung Objektausdrücke) und über Constructor_initializers.Instance constructors are invoked by object_creation_expressions (Object creation expressions) and through constructor_initializers.

KonstruktorinitialisiererConstructor initializers

Alle Instanzkonstruktoren (mit Ausnahme für die Klasse object) sind implizit einen Aufruf des Instanzkonstruktors für eine andere unmittelbar vor der Constructor_body.All instance constructors (except those for class object) implicitly include an invocation of another instance constructor immediately before the constructor_body. Der Konstruktor, der implizit aufgerufen richtet sich nach der Constructor_initializer:The constructor to implicitly invoke is determined by the constructor_initializer:

  • Ein Instanz Konstruktorinitialisierer des Formulars base(argument_list) oder base() bewirkt, dass ein Instanzkonstruktor aus der direkten Basisklasse aufgerufen werden.An instance constructor initializer of the form base(argument_list) or base() causes an instance constructor from the direct base class to be invoked. Dieser Konstruktor wird mit ausgewählt Argument_list wenn vorhanden und die Regeln der überladungsauflösung des Überladungsauflösung.That constructor is selected using argument_list if present and the overload resolution rules of Overload resolution. Der Satz von Kandidaten Instanzkonstruktoren besteht aus allen verfügbaren Instanzkonstruktoren, die in der direkten Basisklasse enthalten oder die Standard-Konstruktor (Standardkonstruktoren), wenn keine Instanzkonstruktoren, in deklariert sind der direkte Basisklasse.The set of candidate instance constructors consists of all accessible instance constructors contained in the direct base class, or the default constructor (Default constructors), if no instance constructors are declared in the direct base class. Wenn dieser Satz leer ist, oder ein einzelnen bewährte Instanzenkonstruktor nicht identifiziert werden kann, tritt ein Fehler während der Kompilierung.If this set is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs.
  • Ein Instanz Konstruktorinitialisierer des Formulars this(argument-list) oder this() bewirkt, dass ein Instanzkonstruktor aus der Klasse selbst aufgerufen werden.An instance constructor initializer of the form this(argument-list) or this() causes an instance constructor from the class itself to be invoked. Der Konstruktor ausgewählt ist, mithilfe von Argument_list wenn vorhanden und die Regeln der überladungsauflösung des Überladungsauflösung.The constructor is selected using argument_list if present and the overload resolution rules of Overload resolution. Der Satz von Kandidaten Instanzkonstruktoren besteht aus allen verfügbaren Instanzkonstruktoren, die in der Klasse selbst deklariert.The set of candidate instance constructors consists of all accessible instance constructors declared in the class itself. Wenn dieser Satz leer ist, oder ein einzelnen bewährte Instanzenkonstruktor nicht identifiziert werden kann, tritt ein Fehler während der Kompilierung.If this set is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs. Wenn eine Instanzkonstruktordeklaration einem Konstruktorinitialisierer, die den Konstruktor selbst aufruft enthält, tritt ein Fehler während der Kompilierung.If an instance constructor declaration includes a constructor initializer that invokes the constructor itself, a compile-time error occurs.

Verfügt ein Instanzkonstruktor ohne Konstruktorinitialisierer, einem Konstruktorinitialisierer des Formulars base() wird impliziert bereitgestellt.If an instance constructor has no constructor initializer, a constructor initializer of the form base() is implicitly provided. Daher eine Instanzkonstruktordeklaration des FormularsThus, an instance constructor declaration of the form

C(...) {...}

ist genau gleichis exactly equivalent to

C(...): base() {...}

Der Bereich der angegebenen Parameter die Formal_parameter_list eines Instanzkonstruktors Deklaration konstruktorinitialisierers diese Deklaration enthält.The scope of the parameters given by the formal_parameter_list of an instance constructor declaration includes the constructor initializer of that declaration. Daher ist einem Konstruktorinitialisierer auf die Parameter des Konstruktors zulässig.Thus, a constructor initializer is permitted to access the parameters of the constructor. Zum Beispiel:For example:

class A
{
    public A(int x, int y) {}
}

class B: A
{
    public B(int x, int y): base(x + y, x - y) {}
}

Ein Konstruktorinitialisierer Instanz kann nicht zu erstellende Instanz zugreifen.An instance constructor initializer cannot access the instance being created. Daher ist es ein Fehler während der Kompilierung auf this in ein Argumentausdruck des konstruktorinitialisierers, wie ist es ein Fehler während der Kompilierung ein Argumentausdruck auf beliebiger Instanzmember über eine Simple_name.Therefore it is a compile-time error to reference this in an argument expression of the constructor initializer, as is it a compile-time error for an argument expression to reference any instance member through a simple_name.

Instanz VariableninitialisierernInstance variable initializers

Wenn ein Instanzkonstruktor hat keinen Konstruktor/Initialisierer aufweisen oder einem Konstruktorinitialisierer des Formulars kann base(...), dieser Konstruktor führt implizit die Initialisierungen, die gemäß der Variable_initializers die Instanzfelder werden in der Klasse deklariert.When an instance constructor has no constructor initializer, or it has a constructor initializer of the form base(...), that constructor implicitly performs the initializations specified by the variable_initializers of the instance fields declared in its class. Dies entspricht einer Sequenz von Zuweisungen, die bei der Eingabe an den Konstruktor und vor den impliziten Aufruf des Konstruktors der direkten Basisklasse sofort ausgeführt werden.This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. Die Variable Initialisierer werden in der Reihenfolge im Text ausgeführt in denen sie in der Klassendeklaration vorkommen.The variable initializers are executed in the textual order in which they appear in the class declaration.

Konstruktor-AusführungConstructor execution

Variableninitialisierern in zuweisungsanweisungen transformiert werden, und diese Anweisungen werden ausgeführt, bevor Sie den Aufruf des Konstruktors der Basisklasse-Instanz.Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the base class instance constructor. Diese Reihenfolge wird sichergestellt, dass alle Instanzenfelder von ihren Variableninitialisierern initialisiert werden, bevor alle Anweisungen, die Zugriff auf diese Instanz ausgeführt werden.This ordering ensures that all instance fields are initialized by their variable initializers before any statements that have access to that instance are executed.

Im Beispiel angegebenGiven the example

using System;

class A
{
    public A() {
        PrintFields();
    }

    public virtual void PrintFields() {}
}

class B: A
{
    int x = 1;
    int y;

    public B() {
        y = -1;
    }

    public override void PrintFields() {
        Console.WriteLine("x = {0}, y = {1}", x, y);
    }
}

Wenn new B() dient zum Erstellen einer Instanz von B, wird die folgende Ausgabe generiert:when new B() is used to create an instance of B, the following output is produced:

x = 1, y = 0

Der Wert des x ist 1, da die Variableninitialisierer ausgeführt wird, bevor der Konstruktor der Basisklasse-Instanz aufgerufen wird.The value of x is 1 because the variable initializer is executed before the base class instance constructor is invoked. Jedoch den Wert der y ist 0 (standardmäßig den Wert ein int) da die Zuweisung zu y wird erst ausgeführt, nachdem Konstruktor der Basisklasse zurückgegeben.However, the value of y is 0 (the default value of an int) because the assignment to y is not executed until after the base class constructor returns.

Es ist hilfreich, die Instanz Variableninitialisierern und Konstruktorinitialisierer wie Anweisungen vorstellen, die automatisch, bevor eingefügt werden die Constructor_body.It is useful to think of instance variable initializers and constructor initializers as statements that are automatically inserted before the constructor_body. Im BeispielThe example

using System;
using System.Collections;

class A
{
    int x = 1, y = -1, count;

    public A() {
        count = 0;
    }

    public A(int n) {
        count = n;
    }
}

class B: A
{
    double sqrt2 = Math.Sqrt(2.0);
    ArrayList items = new ArrayList(100);
    int max;

    public B(): this(100) {
        items.Add("default");
    }

    public B(int n): base(n - 1) {
        max = n;
    }
}

enthält mehrere Variableninitialisierern; Es enthält auch eine Konstruktor-Initialisierungen der beiden Formen (base und this).contains several variable initializers; it also contains constructor initializers of both forms (base and this). Das Beispiel entspricht dem folgenden Code, wobei jeder Kommentar eine automatisch eingefügte Anweisung gibt an, (die Syntax für die Konstruktoraufrufe automatisch eingefügte ist nicht gültig, aber dient lediglich zur Veranschaulichung des Mechanismus).The example corresponds to the code shown below, where each comment indicates an automatically inserted statement (the syntax used for the automatically inserted constructor invocations isn't valid, but merely serves to illustrate the mechanism).

using System.Collections;

class A
{
    int x, y, count;

    public A() {
        x = 1;                       // Variable initializer
        y = -1;                      // Variable initializer
        object();                    // Invoke object() constructor
        count = 0;
    }

    public A(int n) {
        x = 1;                       // Variable initializer
        y = -1;                      // Variable initializer
        object();                    // Invoke object() constructor
        count = n;
    }
}

class B: A
{
    double sqrt2;
    ArrayList items;
    int max;

    public B(): this(100) {
        B(100);                      // Invoke B(int) constructor
        items.Add("default");
    }

    public B(int n): base(n - 1) {
        sqrt2 = Math.Sqrt(2.0);      // Variable initializer
        items = new ArrayList(100);  // Variable initializer
        A(n - 1);                    // Invoke A(int) constructor
        max = n;
    }
}

StandardkonstruktorenDefault constructors

Wenn eine Klasse keine Instanz-Deklarationen enthält, wird automatisch ein Standardkonstruktor für die Instanz bereitgestellt.If a class contains no instance constructor declarations, a default instance constructor is automatically provided. Diese Standard-Konstruktor ruft einfach den parameterlosen Konstruktor der direkten Basisklasse.That default constructor simply invokes the parameterless constructor of the direct base class. Wenn die Klasse abstrakt ist, ist dann die deklarierte Zugriffsart für den Standardkonstruktor geschützt.If the class is abstract then the declared accessibility for the default constructor is protected. Andernfalls ist die deklarierte Zugriffsart für den Standardkonstruktor öffentlich.Otherwise, the declared accessibility for the default constructor is public. Ist daher der Standardkonstruktor immer im FormatThus, the default constructor is always of the form

protected C(): base() {}

oderor

public C(): base() {}

wo C ist der Name der Klasse.where C is the name of the class. Wenn die Auflösung von funktionsüberladungen kann nicht auf einen eindeutige besten Kandidaten für die Basisklasse konstruktorinitialisierers zu bestimmen, und klicken Sie dann ein Fehler während der Kompilierung auftritt.If overload resolution is unable to determine a unique best candidate for the base class constructor initializer then a compile-time error occurs.

Im BeispielIn the example

class Message
{
    object sender;
    string text;
}

ein Standardkonstruktor bereitgestellt, da die Klasse keine Instanz-Deklarationen enthält.a default constructor is provided because the class contains no instance constructor declarations. Daher ist das Beispiel genaue EntsprechungThus, the example is precisely equivalent to

class Message
{
    object sender;
    string text;

    public Message(): base() {}
}

Private KonstruktorenPrivate constructors

Wenn eine Klasse T nur private Instanzkonstruktoren deklariert, ist nicht möglich, dass Klassen außerhalb der Programmtext des T für die Ableitung T oder direkt erstellen von Instanzen von T.When a class T declares only private instance constructors, it is not possible for classes outside the program text of T to derive from T or to directly create instances of T. Daher, wenn eine Klasse nur statische Member enthält und wird nicht instanziiert werden soll, Hinzufügen einer leeren, privaten Instanzkonstruktor Instanziierung verhindert.Thus, if a class contains only static members and isn't intended to be instantiated, adding an empty private instance constructor will prevent instantiation. Zum Beispiel:For example:

public class Trig
{
    private Trig() {}        // Prevent instantiation

    public const double PI = 3.14159265358979323846;

    public static double Sin(double x) {...}
    public static double Cos(double x) {...}
    public static double Tan(double x) {...}
}

Die Trig Klasse Gruppen von verwandten Methoden und Konstanten, aber nicht instanziiert werden soll.The Trig class groups related methods and constants, but is not intended to be instantiated. Aus diesem Grund deklariert einen leeren privaten Instanzkonstruktor.Therefore it declares a single empty private instance constructor. Mindestens ein Instanzkonstruktor muss deklariert werden, um die automatische Generierung des Standardkonstruktors zu unterdrücken.At least one instance constructor must be declared to suppress the automatic generation of a default constructor.

Optionale Instanz KonstruktorparameterOptional instance constructor parameters

Die this(...) Form der Konstruktorinitialisierer wird meist in Verbindung mit der Überladung um optionale Instanz Konstruktorparameter zu implementieren.The this(...) form of constructor initializer is commonly used in conjunction with overloading to implement optional instance constructor parameters. Im BeispielIn the example

class Text
{
    public Text(): this(0, 0, null) {}

    public Text(int x, int y): this(x, y, null) {}

    public Text(int x, int y, string s) {
        // Actual constructor implementation
    }
}

die ersten zwei Instanzkonstruktoren geben lediglich die Standardwerte für die fehlenden Argumente an.the first two instance constructors merely provide the default values for the missing arguments. Beide verwenden eine this(...) Konstruktor/Initialisierer aufweisen, den dritten Instanzkonstruktor aufrufen, sodass die Arbeit wird die neue Instanz initialisiert wird.Both use a this(...) constructor initializer to invoke the third instance constructor, which actually does the work of initializing the new instance. Der Effekt ist der optionale Konstruktorparameter:The effect is that of optional constructor parameters:

Text t1 = new Text();                    // Same as Text(0, 0, null)
Text t2 = new Text(5, 10);               // Same as Text(5, 10, null)
Text t3 = new Text(5, 20, "Hello");

Statische KonstruktorenStatic constructors

Ein statischen Konstruktor ist ein Element, das die erforderlichen Aktionen zum Initialisieren eines geschlossenen Klassentyps implementiert.A static constructor is a member that implements the actions required to initialize a closed class type. Statische Konstruktoren deklariert werden, mithilfe von Static_constructor_declarations:Static constructors are declared using static_constructor_declarations:

static_constructor_declaration
    : attributes? static_constructor_modifiers identifier '(' ')' static_constructor_body
    ;

static_constructor_modifiers
    : 'extern'? 'static'
    | 'static' 'extern'?
    | static_constructor_modifiers_unsafe
    ;

static_constructor_body
    : block
    | ';'
    ;

Ein Static_constructor_declaration eventuell einen Satz von Attribute (Attribute) und ein extern Modifizierer (externe Methoden).A static_constructor_declaration may include a set of attributes (Attributes) and an extern modifier (External methods).

Die Bezeichner von einem Static_constructor_declaration müssen den Namen der Klasse, die in der der statische Konstruktor deklariert wird.The identifier of a static_constructor_declaration must name the class in which the static constructor is declared. Wenn ein anderen Namen angegeben wird, tritt ein Fehler während der Kompilierung.If any other name is specified, a compile-time error occurs.

Wenn eine statische Destruktordeklaration enthält ein extern Modifizierer, der statische Konstruktor gilt eine externen statischen Konstruktor.When a static constructor declaration includes an extern modifier, the static constructor is said to be an external static constructor. Da eine externe statische Destruktordeklaration keine Implementierungen, bietet die Static_constructor_body besteht aus einem Semikolon.Because an external static constructor declaration provides no actual implementation, its static_constructor_body consists of a semicolon. Für alle anderen statischen Konstruktor-Deklarationen die Static_constructor_body besteht aus einem Block der gibt an, die Anweisungen ausführen, um die Klasse zu initialisieren.For all other static constructor declarations, the static_constructor_body consists of a block which specifies the statements to execute in order to initialize the class. Dies entspricht genau der Method_body einer statischen Methode mit einer void Rückgabetyp (Methodentext).This corresponds exactly to the method_body of a static method with a void return type (Method body).

Statische Konstruktoren nicht vererbt werden und nicht direkt aufgerufen werden.Static constructors are not inherited, and cannot be called directly.

Der statische Konstruktor für einen geschlossenen Klassentyp wird höchstens einmal in einer bestimmten Anwendungsdomäne ausgeführt.The static constructor for a closed class type executes at most once in a given application domain. Die Ausführung eines statischen Konstruktors wird durch das erste der folgenden Ereignisse innerhalb einer Anwendungsdomäne ausgelöst:The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

  • Eine Instanz des Klassentyps wird erstellt.An instance of the class type is created.
  • Einer der statischen Member des Klassentyps sind auf die verwiesen wird.Any of the static members of the class type are referenced.

Wenn eine Klasse enthält die Main Methode (Anwendungsstart) in die die Ausführung beginnt, den statischen Konstruktor für diese Klasse vor ausgeführt wird die Main Methode wird aufgerufen.If a class contains the Main method (Application Startup) in which execution begins, the static constructor for that class executes before the Main method is called.

Zum Initialisieren Sie eines neuen geschlossene Klassentyps, zunächst eines neuen Satz von statischen Feldern (statische Felder und Instanzfelder) für den gewählten geschlossen wurde.To initialize a new closed class type, first a new set of static fields (Static and instance fields) for that particular closed type is created. Jedes der statische Felder, die auf den Standardwert initialisiert wird (Standardwerte).Each of the static fields is initialized to its default value (Default values). Anschließend wird die statischen Feldinitialisierer (Initialisierung statischer Felder) für die statische Felder ausgeführt werden.Next, the static field initializers (Static field initialization) are executed for those static fields. Schließlich wird der statische Konstruktor ausgeführt.Finally, the static constructor is executed.

Im BeispielThe example

using System;

class Test
{
    static void Main() {
        A.F();
        B.F();
    }
}

class A
{
    static A() {
        Console.WriteLine("Init A");
    }
    public static void F() {
        Console.WriteLine("A.F");
    }
}

class B
{
    static B() {
        Console.WriteLine("Init B");
    }
    public static void F() {
        Console.WriteLine("B.F");
    }
}

muss die Ausgabe erzeugen:must produce the output:

Init A
A.F
Init B
B.F

Da die Ausführung von Ades statischer Konstruktor wird ausgelöst, durch den Aufruf von A.F, und die Ausführung des Bdes statischer Konstruktor wird ausgelöst, durch den Aufruf von B.F.because the execution of A's static constructor is triggered by the call to A.F, and the execution of B's static constructor is triggered by the call to B.F.

Es ist möglich, die ringabhängigkeiten erstellen, mit denen statische Felder mit Variableninitialisierern an, die im Standardzustand Wert beachtet werden.It is possible to construct circular dependencies that allow static fields with variable initializers to be observed in their default value state.

Im BeispielThe example

using System;

class A
{
    public static int X;

    static A() {
        X = B.Y + 1;
    }
}

class B
{
    public static int Y = A.X + 1;

    static B() {}

    static void Main() {
        Console.WriteLine("X = {0}, Y = {1}", A.X, B.Y);
    }
}

erzeugt die Ausgabeproduces the output

X = 1, Y = 2

Zum Ausführen der Main -Methode, führt das System zunächst den Initialisierer für B.Yvor der Klasse Bdes statischen Konstruktor.To execute the Main method, the system first runs the initializer for B.Y, prior to class B's static constructor. Ydie führt dazu, dass der Initialisierer Ades statischen Konstruktor verfügt, ausgeführt werden, da der Wert des A.X verwiesen wird.Y's initializer causes A's static constructor to be run because the value of A.X is referenced. Der statische Konstruktor des A wiederum geht, der Berechnung des Werts der X, und dies der Fall ist, ruft des Standardwerts von Y, d.h. 0 (null).The static constructor of A in turn proceeds to compute the value of X, and in doing so fetches the default value of Y, which is zero. A.X 1 wird so initialisiert werden.A.X is thus initialized to 1. Der Prozess zur Ausführung Ades statischen Feldinitialisierer und statischen Konstruktor, und klicken Sie dann abgeschlossen ist, und die Berechnung des Anfangswerts der Y, deren Ergebnis ist 2.The process of running A's static field initializers and static constructor then completes, returning to the calculation of the initial value of Y, the result of which becomes 2.

Da der statische Konstruktor genau einmal ausgeführt wird, für jede erstellte Klassentyp geschlossen, es ist eine bequeme Möglichkeit, Überprüfungen zur Laufzeit für den Typparameter zu erzwingen, die zum Zeitpunkt der Kompilierung über die Einschränkungen nicht überprüft werden kann (Typparameter Einschränkungen).Because the static constructor is executed exactly once for each closed constructed class type, it is a convenient place to enforce run-time checks on the type parameter that cannot be checked at compile-time via constraints (Type parameter constraints). Beispielsweise verwendet der folgende Typ einen statischen Konstruktor erzwingen, dass das Typargument eine Enumeration ist:For example, the following type uses a static constructor to enforce that the type argument is an enum:

class Gen<T> where T: struct
{
    static Gen() {
        if (!typeof(T).IsEnum) {
            throw new ArgumentException("T must be an enum");
        }
    }
}

DestruktorenDestructors

Ein Destruktor ist ein Element, das die erforderlichen Aktionen zum zerstört einer Instanz einer Klasse implementiert.A destructor is a member that implements the actions required to destruct an instance of a class. Ein Destruktor deklariert wird, mithilfe einer Destructor_declaration:A destructor is declared using a destructor_declaration:

destructor_declaration
    : attributes? 'extern'? '~' identifier '(' ')' destructor_body
    | destructor_declaration_unsafe
    ;

destructor_body
    : block
    | ';'
    ;

Ein Destructor_declaration eventuell einen Satz von Attribute (Attribute).A destructor_declaration may include a set of attributes (Attributes).

Die Bezeichner von einem Destructor_declaration müssen den Namen der Klasse, die in der der Destruktor deklariert wird.The identifier of a destructor_declaration must name the class in which the destructor is declared. Wenn ein anderen Namen angegeben wird, tritt ein Fehler während der Kompilierung.If any other name is specified, a compile-time error occurs.

Wenn eine Destruktordeklaration enthält eine extern Modifizierer, der Destruktor gilt eine externe Destruktor.When a destructor declaration includes an extern modifier, the destructor is said to be an external destructor. Da eine externe Destruktordeklaration keine Implementierungen, bietet die Destructor_body besteht aus einem Semikolon.Because an external destructor declaration provides no actual implementation, its destructor_body consists of a semicolon. Für alle anderen Destruktoren der Destructor_body besteht aus einem Block der gibt an, die Anweisungen ausführen, um eine Instanz der Klasse zerstört.For all other destructors, the destructor_body consists of a block which specifies the statements to execute in order to destruct an instance of the class. Ein Destructor_body entspricht genau der Method_body einer Instanzmethode mit einer void Rückgabetyp (Methodentext).A destructor_body corresponds exactly to the method_body of an instance method with a void return type (Method body).

Destruktoren werden nicht geerbt.Destructors are not inherited. Daher verfügt über eine Klasse keine Destruktoren, die in dieser Klasse deklariert werden kann.Thus, a class has no destructors other than the one which may be declared in that class.

Da Sie ein Destruktor ohne Parameter erforderlich ist, darf nicht überladene, sein, damit eine Klasse, höchstens einen Destruktor verfügen kann.Since a destructor is required to have no parameters, it cannot be overloaded, so a class can have, at most, one destructor.

Destruktoren werden automatisch aufgerufen und können nicht explizit aufgerufen werden.Destructors are invoked automatically, and cannot be invoked explicitly. Eine Instanz wird zerstört, wenn er nicht mehr möglich, dass jeder Code, verwenden Sie diese Instanz ist.An instance becomes eligible for destruction when it is no longer possible for any code to use that instance. Der Destruktor für die Instanz kann auftreten, zu einem beliebigen Zeitpunkt nach dem die Instanz für die Zerstörung freigegeben wird.Execution of the destructor for the instance may occur at any time after the instance becomes eligible for destruction. Wenn eine Instanz zerstört wird, die Destruktoren in diese Instanz die Vererbungskette werden aufgerufen, in der Reihenfolge, die meisten abgeleitet, um am wenigsten abgeleiteten.When an instance is destructed, the destructors in that instance's inheritance chain are called, in order, from most derived to least derived. Ein Destruktor kann auf jedem Thread ausgeführt werden.A destructor may be executed on any thread. Weitere Informationen zu den Regeln, die steuern, wann und wie ein Destruktor ausgeführt wird, finden Sie unter automatische Speicherverwaltung.For further discussion of the rules that govern when and how a destructor is executed, see Automatic memory management.

Die Ausgabe des BeispielsThe output of the example

using System;

class A
{
    ~A() {
        Console.WriteLine("A's destructor");
    }
}

class B: A
{
    ~B() {
        Console.WriteLine("B's destructor");
    }
}

class Test
{
   static void Main() {
        B b = new B();
        b = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
   }
}

echtis

B's destructor
A's destructor

da Destruktoren in einer Vererbungskette nacheinander aufgerufen werden die meisten abgeleitet, um am wenigsten abgeleiteten.since destructors in an inheritance chain are called in order, from most derived to least derived.

Destruktoren werden durch Überschreiben der virtuellen Methode implementiert Finalize auf System.Object.Destructors are implemented by overriding the virtual method Finalize on System.Object. C#-Programme sind nicht zulässig, diese Methode überschreiben, oder rufen sie (oder überschreibt es) direkt.C# programs are not permitted to override this method or call it (or overrides of it) directly. Beispielsweise das ProgrammFor instance, the program

class A 
{
    override protected void Finalize() {}    // error

    public void F() {
        this.Finalize();                     // error
    }
}

enthält zwei Fehler an.contains two errors.

Der Compiler verhält sich wie diese Methode, und klicken Sie auf Außerkraftsetzungen, überhaupt nicht vorhanden sind.The compiler behaves as if this method, and overrides of it, do not exist at all. Daher ist dieses Programm:Thus, this program:

class A 
{
    void Finalize() {}                            // permitted
}

ist gültig, und die Methode blendet System.Objectdes Finalize Methode.is valid, and the method shown hides System.Object's Finalize method.

Eine Erläuterung des Verhaltens bei der von einem Destruktor eine Ausnahme ausgelöst wird, finden Sie unter Behandlung von Ausnahmen.For a discussion of the behavior when an exception is thrown from a destructor, see How exceptions are handled.

IteratorsIterators

Ein Funktionsmember (Funktionsmember) mit einem Iteratorblock implementiert (Blöcke) wird aufgerufen, eine Iterator.A function member (Function members) implemented using an iterator block (Blocks) is called an iterator.

Kein Iteratorblock kann als Text ein Funktionsmember verwendet werden, solange der Rückgabetyp des entsprechenden Elements Funktion eine der Enumeratorschnittstellen (Enumeratorschnittstellen) mindestens die enumerable-Schnittstellen (Enumerable-Schnittstellen).An iterator block may be used as the body of a function member as long as the return type of the corresponding function member is one of the enumerator interfaces (Enumerator interfaces) or one of the enumerable interfaces (Enumerable interfaces). Es ist möglich, als eine Method_body, Operator_body oder Accessor_body, während Ereignisse, Instanzkonstruktoren, statische Konstruktoren und Destruktoren nicht möglich als Iteratoren implementiert.It can occur as a method_body, operator_body or accessor_body, whereas events, instance constructors, static constructors and destructors cannot be implemented as iterators.

Wenn ein Funktionsmember mit Iteratorblock implementiert ist, es ist ein Fehler während der Kompilierung für die Liste der formalen Parameter, der das Funktionselement zum angeben ref oder out Parameter.When a function member is implemented using an iterator block, it is a compile-time error for the formal parameter list of the function member to specify any ref or out parameters.

Enumerator-SchnittstellenEnumerator interfaces

Die Enumeratorschnittstellen sind die nicht generische Schnittstelle System.Collections.IEnumerator und alle Instanziierungen an der die generische Schnittstelle System.Collections.Generic.IEnumerator<T>.The enumerator interfaces are the non-generic interface System.Collections.IEnumerator and all instantiations of the generic interface System.Collections.Generic.IEnumerator<T>. Aus Gründen der Übersichtlichkeit sind in diesem Kapitel diese Schnittstellen werden auf die verwiesen wird als IEnumerator und IEnumerator<T>bzw.For the sake of brevity, in this chapter these interfaces are referenced as IEnumerator and IEnumerator<T>, respectively.

Aufzählbare SchnittstellenEnumerable interfaces

Die enumerable-Schnittstellen sind die nicht generische Schnittstelle System.Collections.IEnumerable und alle Instanziierungen an der die generische Schnittstelle System.Collections.Generic.IEnumerable<T>.The enumerable interfaces are the non-generic interface System.Collections.IEnumerable and all instantiations of the generic interface System.Collections.Generic.IEnumerable<T>. Aus Gründen der Übersichtlichkeit sind in diesem Kapitel diese Schnittstellen werden auf die verwiesen wird als IEnumerable und IEnumerable<T>bzw.For the sake of brevity, in this chapter these interfaces are referenced as IEnumerable and IEnumerable<T>, respectively.

Yield-TypYield type

Ein Iterator erzeugt eine Sequenz von Werten, alle den gleichen Typ aufweisen.An iterator produces a sequence of values, all of the same type. Dieser Typ wird aufgerufen, die yield-Typ des Iterators.This type is called the yield type of the iterator.

  • Die Yield-Typ, der ein Iterator, der gibt IEnumerator oder IEnumerable ist object.The yield type of an iterator that returns IEnumerator or IEnumerable is object.
  • Die Yield-Typ, der ein Iterator, der gibt IEnumerator<T> oder IEnumerable<T> ist T.The yield type of an iterator that returns IEnumerator<T> or IEnumerable<T> is T.

Enumerator-ObjekteEnumerator objects

Wenn ein Funktionsmember ein Enumerator zurückgegeben, der den Typ mit einem Iteratorblock implementiert ist, wird das Funktionselement Aufrufen nicht sofort den Code im Iteratorblock ausgeführt.When a function member returning an enumerator interface type is implemented using an iterator block, invoking the function member does not immediately execute the code in the iterator block. Stattdessen eine Enumeratorobjekt erstellt und zurückgegeben.Instead, an enumerator object is created and returned. Dieses Objekt kapselt den Code im Iteratorblock angegeben und Ausführung des Codes im Iteratorblock tritt auf, wenn des Enumeratorobjekts MoveNext -Methode wird aufgerufen.This object encapsulates the code specified in the iterator block, and execution of the code in the iterator block occurs when the enumerator object's MoveNext method is invoked. Ein Enumeratorobjekt weist folgende Merkmale auf:An enumerator object has the following characteristics:

  • Es implementiert IEnumerator und IEnumerator<T>, wobei T ist der Yield-Typ des Iterators.It implements IEnumerator and IEnumerator<T>, where T is the yield type of the iterator.
  • Sie implementiert System.IDisposable.It implements System.IDisposable.
  • Initialisiert mit einer Kopie die Argumentwerte gelten (sofern vorhanden) und Instanzwert an das Funktionselement übergeben.It is initialized with a copy of the argument values (if any) and instance value passed to the function member.
  • Hat vier mögliche Zustände, vor, ausführen, angehalten, und nach, und befindet sich zunächst im der vor Zustand.It has four potential states, before, running, suspended, and after, and is initially in the before state.

Ein Enumeratorobjekt ist in der Regel eine Instanz einer vom Compiler generierter Enumerator-Klasse, die den Code im Iteratorblock kapselt und die Enumeratorschnittstellen implementiert, aber andere Methoden der Implementierung sind möglich.An enumerator object is typically an instance of a compiler-generated enumerator class that encapsulates the code in the iterator block and implements the enumerator interfaces, but other methods of implementation are possible. Wenn eine Enumeratorklasse, die vom Compiler generiert wird, wird diese Klasse geschachtelt werden, direkt oder indirekt in der Klasse, die mit das Funktionselement muss private zugriffsmöglichkeiten und muss einen Namen für die Verwendung durch den Compiler reserviert (Bezeichner ).If an enumerator class is generated by the compiler, that class will be nested, directly or indirectly, in the class containing the function member, it will have private accessibility, and it will have a name reserved for compiler use (Identifiers).

Ein Enumeratorobjekt kann mehrere Schnittstellen als die oben angegebenen implementieren.An enumerator object may implement more interfaces than those specified above.

Die folgenden Abschnitte beschreiben das genaue Verhalten der der MoveNext, Current, und Dispose Mitglied der IEnumerable und IEnumerable<T> schnittstellenimplementierungen, die von einem Enumeratorobjekt bereitgestellt.The following sections describe the exact behavior of the MoveNext, Current, and Dispose members of the IEnumerable and IEnumerable<T> interface implementations provided by an enumerator object.

Beachten Sie, dass der Enumerator-Objekte nicht unterstützen die IEnumerator.Reset Methode.Note that enumerator objects do not support the IEnumerator.Reset method. Das Aufrufen dieser Methode bewirkt, dass eine System.NotSupportedException ausgelöst wird.Invoking this method causes a System.NotSupportedException to be thrown.

Die MoveNext-MethodeThe MoveNext method

Die MoveNext Methode eines Enumerators-Objekts kapselt den Code der Iteratorblock.The MoveNext method of an enumerator object encapsulates the code of an iterator block. Aufrufen der MoveNext Methode führt Code in der Iteratorblock und legt die Current Eigenschaft des Enumeratorobjekts nach Bedarf.Invoking the MoveNext method executes code in the iterator block and sets the Current property of the enumerator object as appropriate. Der genaue vom durchgeführten Aktion MoveNext hängt vom Zustand des Enumeratorobjekts beim MoveNext aufgerufen:The precise action performed by MoveNext depends on the state of the enumerator object when MoveNext is invoked:

  • Wenn der Status des Enumeratorobjekts ist vor, wird durch Aufrufen MoveNext:If the state of the enumerator object is before, invoking MoveNext:
    • Ändert den Zustand in ausführen.Changes the state to running.
    • Die Parameter initialisiert (einschließlich this) des Iteratorblocks auf den Argumentwerten und Instanzwert gespeichert, wenn der Enumerator-Objekt initialisiert wurde.Initializes the parameters (including this) of the iterator block to the argument values and instance value saved when the enumerator object was initialized.
    • Führt Iteratorblock von Anfang an, bis die Ausführung unterbrochen wird (siehe Beschreibung unten).Executes the iterator block from the beginning until execution is interrupted (as described below).
  • Wenn der Status des Enumeratorobjekts ist ausführen, das Ergebnis des Aufrufs MoveNext ist nicht angegeben.If the state of the enumerator object is running, the result of invoking MoveNext is unspecified.
  • Wenn der Status des Enumeratorobjekts ist angehalten, wird durch Aufrufen MoveNext:If the state of the enumerator object is suspended, invoking MoveNext:
    • Ändert den Zustand in ausführen.Changes the state to running.
    • Stellt die Werte aller lokalen Variablen und Parameter, die (einschließlich dieses) wieder her Werte, die bei der Ausführung des Iteratorblocks zuletzt angehalten wurde.Restores the values of all local variables and parameters (including this) to the values saved when execution of the iterator block was last suspended. Beachten Sie, dass der Inhalt der alle Objekte, die auf diese Variablen verweist seit dem vorherigen Aufruf von MoveNext geändert haben können.Note that the contents of any objects referenced by these variables may have changed since the previous call to MoveNext.
    • Setzt die Ausführung der Iteratorblock unmittelbar nach der yield return -Anweisung, verursacht das Anhalten der Ausführung und wird fortgesetzt, bis die Ausführung unterbrochen wird (siehe Beschreibung unten).Resumes execution of the iterator block immediately following the yield return statement that caused the suspension of execution and continues until execution is interrupted (as described below).
  • Wenn der Status des Enumeratorobjekts ist nach, wird durch Aufrufen MoveNext gibt false.If the state of the enumerator object is after, invoking MoveNext returns false.

Wenn MoveNext Iteratorblock führt auf vier Arten unterbrochen werden können: Durch eine yield return Anweisung, durch eine yield break Anweisung, durch das Ende der Iteratorblocks auftreten und eine Ausnahme ausgelöst und aus dem Iteratorblock übertragen wird.When MoveNext executes the iterator block, execution can be interrupted in four ways: By a yield return statement, by a yield break statement, by encountering the end of the iterator block, and by an exception being thrown and propagated out of the iterator block.

  • Wenn eine yield return -Anweisung gefunden (die Yield-Anweisung):When a yield return statement is encountered (The yield statement):
    • Die in der Anweisung angegebene Ausdruck wird ausgewertet, implizit in den Typ "yield" konvertiert und zugewiesen der Current Eigenschaft des Enumeratorobjekts.The expression given in the statement is evaluated, implicitly converted to the yield type, and assigned to the Current property of the enumerator object.
    • Die Ausführung des iteratortexts wird angehalten.Execution of the iterator body is suspended. Die Werte aller lokalen Variablen und Parameter (einschließlich this) gespeichert sind, wie der Speicherort dieser yield return Anweisung.The values of all local variables and parameters (including this) are saved, as is the location of this yield return statement. Wenn die yield return -Anweisung ist in einem oder mehreren try blockiert wird, zugeordneten finally Blöcke werden zu diesem Zeitpunkt nicht ausgeführt.If the yield return statement is within one or more try blocks, the associated finally blocks are not executed at this time.
    • Der Status des Enumeratorobjekts wird geändert, um angehalten.The state of the enumerator object is changed to suspended.
    • Die MoveNext Methodenrückgabe true an den Aufrufer, der angibt, dass die Iteration erfolgreich auf den nächsten Wert gesetzt.The MoveNext method returns true to its caller, indicating that the iteration successfully advanced to the next value.
  • Wenn eine yield break -Anweisung gefunden (die Yield-Anweisung):When a yield break statement is encountered (The yield statement):
    • Wenn die yield break -Anweisung ist in einem oder mehreren try blockiert wird, zugeordneten finally -blocke ausgeführt werden.If the yield break statement is within one or more try blocks, the associated finally blocks are executed.
    • Der Status des Enumeratorobjekts wird geändert, um nach.The state of the enumerator object is changed to after.
    • Die MoveNext Methodenrückgabe false an den Aufrufer, der angibt, dass die Iteration abgeschlossen ist.The MoveNext method returns false to its caller, indicating that the iteration is complete.
  • Wenn das Ende des iteratortexts erreicht wird:When the end of the iterator body is encountered:
    • Der Status des Enumeratorobjekts wird geändert, um nach.The state of the enumerator object is changed to after.
    • Die MoveNext Methodenrückgabe false an den Aufrufer, der angibt, dass die Iteration abgeschlossen ist.The MoveNext method returns false to its caller, indicating that the iteration is complete.
  • Wenn eine Ausnahme ausgelöst und aus dem Iteratorblock übertragen:When an exception is thrown and propagated out of the iterator block:
    • Entsprechende finally Blöcke im des iteratortexts werden durch die ausnahmeweitergabe ausgeführt wurden.Appropriate finally blocks in the iterator body will have been executed by the exception propagation.
    • Der Status des Enumeratorobjekts wird geändert, um nach.The state of the enumerator object is changed to after.
    • Die ausnahmeweitergabe wird fortgesetzt, an den Aufrufer von der MoveNext Methode.The exception propagation continues to the caller of the MoveNext method.

Die Current-EigenschaftThe Current property

Ein Enumeratorobjekt Current Eigenschaft betroffen yield return Anweisungen im Iteratorblock.An enumerator object's Current property is affected by yield return statements in the iterator block.

Wenn ein Enumeratorobjekt ist der angehalten Zustand, den Wert der Current ist der Wert festlegen, indem dem vorherigen Aufruf von MoveNext.When an enumerator object is in the suspended state, the value of Current is the value set by the previous call to MoveNext. Wenn ein Enumeratorobjekt ist der vor, ausgeführt, oder nach angibt, das Ergebnis des Zugriffs auf Current ist nicht angegeben.When an enumerator object is in the before, running, or after states, the result of accessing Current is unspecified.

Geben Sie für einen Iterator mit einem "yield" als object, das Ergebnis des Zugriffs auf Current über des Enumeratorobjekts IEnumerable Implementierung entspricht, für den Zugriff auf Current über des Enumeratorobjekts IEnumerator<T> Implementierung und das Ergebnis umwandeln object.For an iterator with a yield type other than object, the result of accessing Current through the enumerator object's IEnumerable implementation corresponds to accessing Current through the enumerator object's IEnumerator<T> implementation and casting the result to object.

Die Dispose-MethodeThe Dispose method

Die Dispose Methode wird verwendet, um die Iteration zu bereinigen, indem Sie direkt die Enumerator-Objekt an die nach Zustand.The Dispose method is used to clean up the iteration by bringing the enumerator object to the after state.

  • Wenn der Status des Enumeratorobjekts ist vor, wird durch Aufrufen Dispose ändert den Zustand in nach.If the state of the enumerator object is before, invoking Dispose changes the state to after.
  • Wenn der Status des Enumeratorobjekts ist ausführen, das Ergebnis des Aufrufs Dispose ist nicht angegeben.If the state of the enumerator object is running, the result of invoking Dispose is unspecified.
  • Wenn der Status des Enumeratorobjekts ist angehalten, wird durch Aufrufen Dispose:If the state of the enumerator object is suspended, invoking Dispose:
    • Ändert den Zustand in ausführen.Changes the state to running.
    • Führt alle schließlich Blöcke, als ob die zuletzt ausgeführte yield return Anweisung wurden eine yield break Anweisung.Executes any finally blocks as if the last executed yield return statement were a yield break statement. Wenn dies bewirkt, eine Ausnahme ausgelöst und aus dem Iterator-Text übertragen werden dass, ist der Status des Enumeratorobjekts auf festgelegt nach und die Ausnahme wird an den Aufrufer der übertragen die Dispose Methode.If this causes an exception to be thrown and propagated out of the iterator body, the state of the enumerator object is set to after and the exception is propagated to the caller of the Dispose method.
    • Ändert den Zustand in nach.Changes the state to after.
  • Wenn der Status des Enumeratorobjekts ist nach, wird durch Aufrufen Dispose hat keine Auswirkungen.If the state of the enumerator object is after, invoking Dispose has no affect.

Aufzählbare ObjekteEnumerable objects

Wenn ein Funktionsmember einen enumerable Schnittstellentyp zurückgeben mit einem Iteratorblock implementiert ist, wird das Funktionselement Aufrufen nicht sofort den Code im Iteratorblock ausgeführt.When a function member returning an enumerable interface type is implemented using an iterator block, invoking the function member does not immediately execute the code in the iterator block. Stattdessen eine aufzählbares Objekt erstellt und zurückgegeben.Instead, an enumerable object is created and returned. Des aufzählbaren Objekts GetEnumerator Methode gibt ein Enumeratorobjekt, das den Code kapselt im Iteratorblock angegeben und Ausführung des Codes im Iteratorblock tritt auf, wenn des Enumeratorobjekts MoveNext -Methode wird aufgerufen.The enumerable object's GetEnumerator method returns an enumerator object that encapsulates the code specified in the iterator block, and execution of the code in the iterator block occurs when the enumerator object's MoveNext method is invoked. Ein aufzählbares Objekt weist folgende Merkmale auf:An enumerable object has the following characteristics:

  • Es implementiert IEnumerable und IEnumerable<T>, wobei T ist der Yield-Typ des Iterators.It implements IEnumerable and IEnumerable<T>, where T is the yield type of the iterator.
  • Initialisiert mit einer Kopie die Argumentwerte gelten (sofern vorhanden) und Instanzwert an das Funktionselement übergeben.It is initialized with a copy of the argument values (if any) and instance value passed to the function member.

Ein aufzählbares Objekt ist in der Regel eine Instanz einer vom Compiler generierter enumerable-Klasse, die den Code im Iteratorblock kapselt und die enumerable-Schnittstellen implementiert, aber andere Methoden der Implementierung sind möglich.An enumerable object is typically an instance of a compiler-generated enumerable class that encapsulates the code in the iterator block and implements the enumerable interfaces, but other methods of implementation are possible. Wenn eine enumerable-Klasse, die vom Compiler generiert wird, wird diese Klasse geschachtelt werden, direkt oder indirekt in der Klasse, die mit das Funktionselement muss private zugriffsmöglichkeiten und muss einen Namen für die Verwendung durch den Compiler reserviert (Bezeichner ).If an enumerable class is generated by the compiler, that class will be nested, directly or indirectly, in the class containing the function member, it will have private accessibility, and it will have a name reserved for compiler use (Identifiers).

Ein aufzählbares Objekt möglicherweise mehr als die oben angegebenen Schnittstellen.An enumerable object may implement more interfaces than those specified above. Insbesondere kann ein aufzählbares Objekt auch implementieren IEnumerator und IEnumerator<T>, er ermöglicht, sowohl als ein aufzählbares Element einen Enumerator dient.In particular, an enumerable object may also implement IEnumerator and IEnumerator<T>, enabling it to serve as both an enumerable and an enumerator. In dieser Art der Implementierung, die beim ersten Öffnen eines aufzählbaren Objekts GetEnumerator Methode wird aufgerufen, das aufzählbare Objekt selbst wird zurückgegeben.In that type of implementation, the first time an enumerable object's GetEnumerator method is invoked, the enumerable object itself is returned. Nachfolgende Aufrufe von des aufzählbaren Objekts GetEnumerator, sofern vorhanden, die eine Kopie des aufzählbaren Objekts zurückgeben.Subsequent invocations of the enumerable object's GetEnumerator, if any, return a copy of the enumerable object. Daher zurückgegeben jeder Enumerator hat seinen eigenen Status und Änderungen in einem Enumerator hat keinen Einfluss auf einen anderen.Thus, each returned enumerator has its own state and changes in one enumerator will not affect another.

Der GetEnumerator-MethodeThe GetEnumerator method

Ein aufzählbares Objekt stellt eine Implementierung der GetEnumerator Methoden der IEnumerable und IEnumerable<T> Schnittstellen.An enumerable object provides an implementation of the GetEnumerator methods of the IEnumerable and IEnumerable<T> interfaces. Die beiden GetEnumerator Methoden gemeinsam nutzen, eine gängige Implementierung, die reserviert, und gibt ein verfügbaren Enumeratorobjekt zurück.The two GetEnumerator methods share a common implementation that acquires and returns an available enumerator object. Das Enumeratorobjekt mit den Argumentwerten initialisiert wird und der Instanz ein Wert gespeichert, wenn das aufzählbare Objekt initialisiert, aber ansonsten wurde die Enumerator-Objekt-Funktionen wie in beschrieben Enumeratorobjekte.The enumerator object is initialized with the argument values and instance value saved when the enumerable object was initialized, but otherwise the enumerator object functions as described in Enumerator objects.

Beispiel für die ImplementierungImplementation example

Dieser Abschnitt beschreibt eine mögliche Implementierung der Iteratoren in Bezug auf die standardmäßige C#-Konstrukte.This section describes a possible implementation of iterators in terms of standard C# constructs. Die hier beschriebene Implementierung basiert darauf, dass die gleichen Prinzipien, die vom Microsoft C#-Compiler verwendet, aber es ist keine beauftragten Implementierung oder das einzig mögliche.The implementation described here is based on the same principles used by the Microsoft C# compiler, but it is by no means a mandated implementation or the only one possible.

Die folgenden Stack<T> -Klasse implementiert die GetEnumerator Methode, die mithilfe eines Iterators.The following Stack<T> class implements its GetEnumerator method using an iterator. Der Iterator Listet die Elemente des Stapels in von oben nach unten.The iterator enumerates the elements of the stack in top to bottom order.

using System;
using System.Collections;
using System.Collections.Generic;

class Stack<T>: IEnumerable<T>
{
    T[] items;
    int count;

    public void Push(T item) {
        if (items == null) {
            items = new T[4];
        }
        else if (items.Length == count) {
            T[] newItems = new T[count * 2];
            Array.Copy(items, 0, newItems, 0, count);
            items = newItems;
        }
        items[count++] = item;
    }

    public T Pop() {
        T result = items[--count];
        items[count] = default(T);
        return result;
    }

    public IEnumerator<T> GetEnumerator() {
        for (int i = count - 1; i >= 0; --i) yield return items[i];
    }
}

Die GetEnumerator Methode kann in eine Instanziierung einer vom Compiler generierter Enumerator-Klasse, die den Code im Iteratorblock kapselt übersetzt werden, wie im folgenden dargestellt.The GetEnumerator method can be translated into an instantiation of a compiler-generated enumerator class that encapsulates the code in the iterator block, as shown in the following.

class Stack<T>: IEnumerable<T>
{
    ...

    public IEnumerator<T> GetEnumerator() {
        return new __Enumerator1(this);
    }

    class __Enumerator1: IEnumerator<T>, IEnumerator
    {
        int __state;
        T __current;
        Stack<T> __this;
        int i;

        public __Enumerator1(Stack<T> __this) {
            this.__this = __this;
        }

        public T Current {
            get { return __current; }
        }

        object IEnumerator.Current {
            get { return __current; }
        }

        public bool MoveNext() {
            switch (__state) {
                case 1: goto __state1;
                case 2: goto __state2;
            }
            i = __this.count - 1;
        __loop:
            if (i < 0) goto __state2;
            __current = __this.items[i];
            __state = 1;
            return true;
        __state1:
            --i;
            goto __loop;
        __state2:
            __state = 2;
            return false;
        }

        public void Dispose() {
            __state = 2;
        }

        void IEnumerator.Reset() {
            throw new NotSupportedException();
        }
    }
}

Der Code im Iteratorblock in einen Zustandsautomaten aktiviert ist, und die in der vorherigen Übersetzung, platziert Sie der MoveNext -Methode der Enumerator-Klasse.In the preceding translation, the code in the iterator block is turned into a state machine and placed in the MoveNext method of the enumerator class. Darüber hinaus die lokale Variable i in ein Feld im Enumerator-Objekt aktiviert ist, damit er fortfahren kann, über Aufrufe der vorhanden sein, MoveNext.Furthermore, the local variable i is turned into a field in the enumerator object so it can continue to exist across invocations of MoveNext.

Im folgende Beispiel wird eine einfache Tabelle der Multiplikation von ganzen Zahlen 1 bis 10 gedruckt.The following example prints a simple multiplication table of the integers 1 through 10. Die FromTo -Methode im Beispiel gibt ein aufzählbares Objekt zurück und wird mithilfe eines Iterators implementiert.The FromTo method in the example returns an enumerable object and is implemented using an iterator.

using System;
using System.Collections.Generic;

class Test
{
    static IEnumerable<int> FromTo(int from, int to) {
        while (from <= to) yield return from++;
    }

    static void Main() {
        IEnumerable<int> e = FromTo(1, 10);
        foreach (int x in e) {
            foreach (int y in e) {
                Console.Write("{0,3} ", x * y);
            }
            Console.WriteLine();
        }
    }
}

Die FromTo Methode kann in eine Instanziierung einer vom Compiler generierter enumerable-Klasse, die den Code im Iteratorblock kapselt übersetzt werden, wie im folgenden dargestellt.The FromTo method can be translated into an instantiation of a compiler-generated enumerable class that encapsulates the code in the iterator block, as shown in the following.

using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

class Test
{
    ...

    static IEnumerable<int> FromTo(int from, int to) {
        return new __Enumerable1(from, to);
    }

    class __Enumerable1:
        IEnumerable<int>, IEnumerable,
        IEnumerator<int>, IEnumerator
    {
        int __state;
        int __current;
        int __from;
        int from;
        int to;
        int i;

        public __Enumerable1(int __from, int to) {
            this.__from = __from;
            this.to = to;
        }

        public IEnumerator<int> GetEnumerator() {
            __Enumerable1 result = this;
            if (Interlocked.CompareExchange(ref __state, 1, 0) != 0) {
                result = new __Enumerable1(__from, to);
                result.__state = 1;
            }
            result.from = result.__from;
            return result;
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return (IEnumerator)GetEnumerator();
        }

        public int Current {
            get { return __current; }
        }

        object IEnumerator.Current {
            get { return __current; }
        }

        public bool MoveNext() {
            switch (__state) {
            case 1:
                if (from > to) goto case 2;
                __current = from++;
                __state = 1;
                return true;
            case 2:
                __state = 2;
                return false;
            default:
                throw new InvalidOperationException();
            }
        }

        public void Dispose() {
            __state = 2;
        }

        void IEnumerator.Reset() {
            throw new NotSupportedException();
        }
    }
}

Die enumerable-Klasse implementiert sowohl die enumerable-Schnittstellen als auch die Enumeratorschnittstellen, die er ermöglicht, sowohl als ein aufzählbares Element einen Enumerator dient.The enumerable class implements both the enumerable interfaces and the enumerator interfaces, enabling it to serve as both an enumerable and an enumerator. Beim ersten die GetEnumerator Methode wird aufgerufen, das aufzählbare Objekt selbst wird zurückgegeben.The first time the GetEnumerator method is invoked, the enumerable object itself is returned. Nachfolgende Aufrufe von des aufzählbaren Objekts GetEnumerator, sofern vorhanden, die eine Kopie des aufzählbaren Objekts zurückgeben.Subsequent invocations of the enumerable object's GetEnumerator, if any, return a copy of the enumerable object. Daher zurückgegeben jeder Enumerator hat seinen eigenen Status und Änderungen in einem Enumerator hat keinen Einfluss auf einen anderen.Thus, each returned enumerator has its own state and changes in one enumerator will not affect another. Die Interlocked.CompareExchange Methode wird verwendet, um die Thread-sichere Betrieb sicherzustellen.The Interlocked.CompareExchange method is used to ensure thread-safe operation.

Die from und to Parameter werden in die Felder in der enumerable-Klasse umgewandelt.The from and to parameters are turned into fields in the enumerable class. Da from geändert wird, im Iteratorblock, eine zusätzliche __from Feld wird eingeführt, um den ersten Wert speichern from in foreach-Enumerator.Because from is modified in the iterator block, an additional __from field is introduced to hold the initial value given to from in each enumerator.

Die MoveNext -Methode löst eine InvalidOperationException , wenn er, wenn aufgerufen wird __state ist 0.The MoveNext method throws an InvalidOperationException if it is called when __state is 0. Dies schützt vor der Verwendung des aufzählbaren Objekts als ein Enumeratorobjekt erst nach Aufrufen von GetEnumerator.This protects against use of the enumerable object as an enumerator object without first calling GetEnumerator.

Das folgende Beispiel zeigt eine einfache Struktur-Klasse.The following example shows a simple tree class. Die Tree<T> -Klasse implementiert die GetEnumerator Methode, die mithilfe eines Iterators.The Tree<T> class implements its GetEnumerator method using an iterator. Der Iterator Listet die Elemente der Struktur in Infix-Reihenfolge.The iterator enumerates the elements of the tree in infix order.

using System;
using System.Collections.Generic;

class Tree<T>: IEnumerable<T>
{
    T value;
    Tree<T> left;
    Tree<T> right;

    public Tree(T value, Tree<T> left, Tree<T> right) {
        this.value = value;
        this.left = left;
        this.right = right;
    }

    public IEnumerator<T> GetEnumerator() {
        if (left != null) foreach (T x in left) yield x;
        yield value;
        if (right != null) foreach (T x in right) yield x;
    }
}

class Program
{
    static Tree<T> MakeTree<T>(T[] items, int left, int right) {
        if (left > right) return null;
        int i = (left + right) / 2;
        return new Tree<T>(items[i], 
            MakeTree(items, left, i - 1),
            MakeTree(items, i + 1, right));
    }

    static Tree<T> MakeTree<T>(params T[] items) {
        return MakeTree(items, 0, items.Length - 1);
    }

    // The output of the program is:
    // 1 2 3 4 5 6 7 8 9
    // Mon Tue Wed Thu Fri Sat Sun

    static void Main() {
        Tree<int> ints = MakeTree(1, 2, 3, 4, 5, 6, 7, 8, 9);
        foreach (int i in ints) Console.Write("{0} ", i);
        Console.WriteLine();

        Tree<string> strings = MakeTree(
            "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun");
        foreach (string s in strings) Console.Write("{0} ", s);
        Console.WriteLine();
    }
}

Die GetEnumerator Methode kann in eine Instanziierung einer vom Compiler generierter Enumerator-Klasse, die den Code im Iteratorblock kapselt übersetzt werden, wie im folgenden dargestellt.The GetEnumerator method can be translated into an instantiation of a compiler-generated enumerator class that encapsulates the code in the iterator block, as shown in the following.

class Tree<T>: IEnumerable<T>
{
    ...

    public IEnumerator<T> GetEnumerator() {
        return new __Enumerator1(this);
    }

    class __Enumerator1 : IEnumerator<T>, IEnumerator
    {
        Node<T> __this;
        IEnumerator<T> __left, __right;
        int __state;
        T __current;

        public __Enumerator1(Node<T> __this) {
            this.__this = __this;
        }

        public T Current {
            get { return __current; }
        }

        object IEnumerator.Current {
            get { return __current; }
        }

        public bool MoveNext() {
            try {
                switch (__state) {

                case 0:
                    __state = -1;
                    if (__this.left == null) goto __yield_value;
                    __left = __this.left.GetEnumerator();
                    goto case 1;

                case 1:
                    __state = -2;
                    if (!__left.MoveNext()) goto __left_dispose;
                    __current = __left.Current;
                    __state = 1;
                    return true;

                __left_dispose:
                    __state = -1;
                    __left.Dispose();

                __yield_value:
                    __current = __this.value;
                    __state = 2;
                    return true;

                case 2:
                    __state = -1;
                    if (__this.right == null) goto __end;
                    __right = __this.right.GetEnumerator();
                    goto case 3;

                case 3:
                    __state = -3;
                    if (!__right.MoveNext()) goto __right_dispose;
                    __current = __right.Current;
                    __state = 3;
                    return true;

                __right_dispose:
                    __state = -1;
                    __right.Dispose();

                __end:
                    __state = 4;
                    break;

                }
            }
            finally {
                if (__state < 0) Dispose();
            }
            return false;
        }

        public void Dispose() {
            try {
                switch (__state) {

                case 1:
                case -2:
                    __left.Dispose();
                    break;

                case 3:
                case -3:
                    __right.Dispose();
                    break;

                }
            }
            finally {
                __state = 4;
            }
        }

        void IEnumerator.Reset() {
            throw new NotSupportedException();
        }
    }
}

Die vom Compiler generierten temporären Dateien, die in verwendet die foreach Anweisungen werden herausgehoben, in der __left und __right Felder des Enumeratorobjekts.The compiler generated temporaries used in the foreach statements are lifted into the __left and __right fields of the enumerator object. Die __state Feld des Enumeratorobjekts sorgfältig aktualisiert, damit die richtige Dispose() Methode wird ordnungsgemäß aufgerufen werden, wenn eine Ausnahme ausgelöst wird.The __state field of the enumerator object is carefully updated so that the correct Dispose() method will be called correctly if an exception is thrown. Beachten Sie, dass es nicht möglich, schreiben den übersetzten Code mit einfachen foreach Anweisungen.Note that it is not possible to write the translated code with simple foreach statements.

Asynchrone FunktionenAsync functions

Eine Methode (Methoden) oder eine anonyme Funktion (anonyme Funktionsausdrücke) mit der async Modifizierer wird aufgerufen, eine Async-Funktion.A method (Methods) or anonymous function (Anonymous function expressions) with the async modifier is called an async function. Im Allgemeinen den Begriff Async wird verwendet, um jede Art von Funktion beschreiben, das die async Modifizierer.In general, the term async is used to describe any kind of function that has the async modifier.

Es ist ein Fehler während der Kompilierung für die Liste der formalen Parameter zum Angeben einer Async-Funktion ref oder out Parameter.It is a compile-time error for the formal parameter list of an async function to specify any ref or out parameters.

Die Return_type von Async-Methode muss entweder void oder Aufgabentyp.The return_type of an async method must be either void or a task type. Die Tasktypen sind System.Threading.Tasks.Task und Typen aus System.Threading.Tasks.Task<T>.The task types are System.Threading.Tasks.Task and types constructed from System.Threading.Tasks.Task<T>. Aus Gründen der Übersichtlichkeit sind in diesem Kapitel diese Typen verwiesen wird als Task und Task<T>bzw.For the sake of brevity, in this chapter these types are referenced as Task and Task<T>, respectively. Eine asynchrone Methode zurückgeben von Typ "Task" wird als Task zurückgeben bezeichnet.An async method returning a task type is said to be task-returning.

Die genaue Definition der Tasktypen ist die Implementierung definiert, aber aus Sicht der Sprache wird Typ "Task" in einem der Zustände nicht abgeschlossen wurde, erfolgreich war oder fehlgeschlagen ist.The exact definition of the task types is implementation defined, but from the language's point of view a task type is in one of the states incomplete, succeeded or faulted. Eine fehlgeschlagene Aufgabe zeichnet eine wichtige Ausnahme.A faulted task records a pertinent exception. Eine erfolgreiche Task<T> zeichnet ein Ergebnis vom Typ T.A succeeded Task<T> records a result of type T. Tasktypen sind "awaitable", und können daher die Operanden des await-Ausdrücken (Await-Ausdrücken).Task types are awaitable, and can therefore be the operands of await expressions (Await expressions).

Eine Async-Funktionsaufruf bietet die Möglichkeit, die Auswertung Anhalten von await-Ausdrücken (Await-Ausdrücken) in ihrem Text.An async function invocation has the ability to suspend evaluation by means of await expressions (Await expressions) in its body. Auswertung kann später fortgesetzt werden, zum Zeitpunkt der anhalten await-Ausdruck von einem Wiederaufnahmedelegat.Evaluation may later be resumed at the point of the suspending await expression by means of a resumption delegate. Der Wiederaufnahmedelegat ist vom Typ System.Action, und wenn er aufgerufen wird, wird Auswertung der Async-Funktionsaufruf aus der Await-Ausdruck, der an der Stelle fortgesetzt.The resumption delegate is of type System.Action, and when it is invoked, evaluation of the async function invocation will resume from the await expression where it left off. Die aktuellen Aufrufer einer asynchronen Funktion Aufruf ist des ursprünglichen Aufrufers, wenn der Funktionsaufruf nie angehalten wurde, oder der letzte Aufrufer der Wiederaufnahmedelegat andernfalls.The current caller of an async function invocation is the original caller if the function invocation has never been suspended, or the most recent caller of the resumption delegate otherwise.

Eine Aufgabe zurückgibt Async-FunktionEvaluation of a task-returning async function

Aufruf einer Aufgabe zurückgibt Async-Funktion bewirkt, dass eine Instanz des Typs die zurückgegebene Aufgabe generiert werden soll.Invocation of a task-returning async function causes an instance of the returned task type to be generated. Dies wird aufgerufen, die Task zurückgeben der Async-Funktion.This is called the return task of the async function. Der Task ist anfangs in einem unvollständigen Status.The task is initially in an incomplete state.

Der Hauptteil der Async-Funktion wird dann ausgewertet bis sie (durch erreichen einen Await-Ausdruck) entweder angehalten oder beendet wird, an dem Verwaltungspunkt-Steuerungs an den Aufrufer, zusammen mit dem Rückgabewert Task zurückgegeben.The async function body is then evaluated until it is either suspended (by reaching an await expression) or terminates, at which point control is returned to the caller, along with the return task.

Wenn der Hauptteil der Async-Funktion beendet wird, wird die return-Aufgabe beendet den unvollständigen Zustand verschoben:When the body of the async function terminates, the return task is moved out of the incomplete state:

  • Wenn der Hauptteil der Funktion als Ergebnis erreicht wird, eine return-Anweisung oder das Ende des Texts beendet wird, wird alle Ergebniswert in der Aufgabe zurückgeben aufgezeichnet, die in einem Zustand "erfolgreich" versetzt wird.If the function body terminates as the result of reaching a return statement or the end of the body, any result value is recorded in the return task, which is put into a succeeded state.
  • Wenn der Hauptteil der Funktion als Ergebnis einer nicht abgefangenen Ausnahme beendet wird (die Throw-Anweisung) wird die Ausnahme in der return-Aufgabe das in einem fehlerhaften Zustand versetzt wird aufgezeichnet.If the function body terminates as the result of an uncaught exception (The throw statement) the exception is recorded in the return task which is put into a faulted state.

Auswertung einer "void" zurückgebende asynchrone-FunktionEvaluation of a void-returning async function

Wenn der Rückgabetyp der asynchronen Funktion void, Auswertung unterscheidet sich von den oben genannten auf folgende Weise: Da keine Aufgabe zurückgegeben wird, kommuniziert die Funktion Vervollständigung und Ausnahmen für des aktuellen Threads stattdessen Synchronisierungskontext.If the return type of the async function is void, evaluation differs from the above in the following way: Because no task is returned, the function instead communicates completion and exceptions to the current thread's synchronization context. Die genaue Definition von Synchronisierungskontext ist implementierungsabhängig, aber es ist eine Darstellung des "where" der aktuelle Thread ausgeführt wird.The exact definition of synchronization context is implementation-dependent, but is a representation of "where" the current thread is running. Der Synchronisierungskontext wird benachrichtigt, wenn es sich bei Auswertung einer "void" zurückgebende asynchrone Funktion beginnt, wird erfolgreich abgeschlossen oder führt dazu, dass eine nicht abgefangene Ausnahme ausgelöst wird.The synchronization context is notified when evaluation of a void-returning async function commences, completes successfully, or causes an uncaught exception to be thrown.

Dadurch wird den Kontext, behalten Sie verfolgen, wie viele "void" zurückgebende asynchrone Funktionen, darunter ausgeführt werden, und klicken Sie, wie Ausnahmen, die sie stammenden weitergegeben werden soll.This allows the context to keep track of how many void-returning async functions are running under it, and to decide how to propagate exceptions coming out of them.