AusdrückeExpressions

Ein Ausdruck ist eine Folge von Operatoren und Operanden.An expression is a sequence of operators and operands. In diesem Kapitel werden die Syntax, die Reihenfolge der Auswertung von Operanden und Operatoren sowie die Bedeutung von Ausdrücken definiert.This chapter defines the syntax, order of evaluation of operands and operators, and meaning of expressions.

Expression classifications (Ausdrucksklassifizierungen)Expression classifications

Ein Ausdruck ist eines der folgenden Elemente:An expression is classified as one of the following:

  • Ein Wert.A value. Jeder Wert verfügt über einen zugeordneten Typ.Every value has an associated type.
  • Eine Variable.A variable. Jede Variable verfügt über einen zugeordneten Typ, nämlich den deklarierten Typ der Variablen.Every variable has an associated type, namely the declared type of the variable.
  • Ein Namespace.A namespace. Ein Ausdruck mit dieser Klassifizierung kann nur auf der linken Seite eines member_access (Member Access) angezeigt werden.An expression with this classification can only appear as the left hand side of a member_access (Member access). In jedem anderen Kontext verursacht ein Ausdruck, der als Namespace klassifiziert ist, einen Kompilierzeitfehler.In any other context, an expression classified as a namespace causes a compile-time error.
  • Ein Typ.A type. Ein Ausdruck mit dieser Klassifizierung kann nur als linke Seite eines member_access (Member Access) oder als Operand für den as Operator (as-Operator), is Operator (is-Operator) oder typeof Operator (der typeof-Operator) angezeigt werden.An expression with this classification can only appear as the left hand side of a member_access (Member access), or as an operand for the as operator (The as operator), the is operator (The is operator), or the typeof operator (The typeof operator). In jedem anderen Kontext verursacht ein Ausdruck, der als Typ klassifiziert ist, einen Kompilierzeitfehler.In any other context, an expression classified as a type causes a compile-time error.
  • Eine Methoden Gruppe, bei der es sich um eine Reihe von überladenen Methoden handelt, die sich aus einer Element Suche (Member Suche) ergeben.A method group, which is a set of overloaded methods resulting from a member lookup (Member lookup). Eine Methoden Gruppe kann über einen zugeordneten Instanzausdruck und eine zugeordnete Typargument Liste verfügen.A method group may have an associated instance expression and an associated type argument list. Wenn eine Instanzmethode aufgerufen wird, wird das Ergebnis der Auswertung des Instanzausdrucks zu der durch dargestellten Instanz this (dieser Zugriff).When an instance method is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access). Eine Methoden Gruppe ist in einem invocation_expression (Aufruf Ausdrücke), einem delegate_creation_expression (delegaterstellungs Ausdruck) und als linke Seite eines is-Operators zulässig und kann implizit in einen kompatiblen Delegattyp (Methoden Gruppen Konvertierungen) konvertiert werden.A method group is permitted in an invocation_expression (Invocation expressions) , a delegate_creation_expression (Delegate creation expressions) and as the left hand side of an is operator, and can be implicitly converted to a compatible delegate type (Method group conversions). In jedem anderen Kontext verursacht ein Ausdruck, der als Methoden Gruppe klassifiziert ist, einen Kompilierzeitfehler.In any other context, an expression classified as a method group causes a compile-time error.
  • Ein NULL-Literale.A null literal. Ein Ausdruck mit dieser Klassifizierung kann implizit in einen Verweistyp oder einen Werte zulässt-Typ konvertiert werden.An expression with this classification can be implicitly converted to a reference type or nullable type.
  • Eine anonyme Funktion.An anonymous function. Ein Ausdruck mit dieser Klassifizierung kann implizit in einen kompatiblen Delegattyp oder Ausdrucks Strukturtyp konvertiert werden.An expression with this classification can be implicitly converted to a compatible delegate type or expression tree type.
  • Ein Eigenschaften Zugriff.A property access. Jeder Eigenschaften Zugriff verfügt über einen zugeordneten Typ, nämlich den Typ der Eigenschaft.Every property access has an associated type, namely the type of the property. Außerdem kann ein Eigenschaften Zugriff über einen zugeordneten Instanzausdruck verfügen.Furthermore, a property access may have an associated instance expression. Wenn ein Accessor (der- get oder- set Block) eines Instanzeigenschaft Zugriffs aufgerufen wird, wird das Ergebnis der Auswertung des Instanzausdrucks zu der durch dargestellten Instanz this (dieser Zugriff).When an accessor (the get or set block) of an instance property access is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access).
  • Ein Ereignis Zugriff.An event access. Jedem Ereignis Zugriff ist ein Typ zugeordnet, nämlich der Typ des Ereignisses.Every event access has an associated type, namely the type of the event. Außerdem kann ein Ereignis Zugriff über einen zugeordneten Instanzausdruck verfügen.Furthermore, an event access may have an associated instance expression. Ein Ereignis Zugriff kann als Linker Operand des += -= Operators und (Ereignis Zuweisung) angezeigt werden.An event access may appear as the left hand operand of the += and -= operators (Event assignment). In jedem anderen Kontext verursacht ein Ausdruck, der als Ereignis Zugriff klassifiziert ist, einen Kompilierzeitfehler.In any other context, an expression classified as an event access causes a compile-time error.
  • Ein Indexer-Zugriff.An indexer access. Jedem Indexer-Zugriff ist ein Typ zugeordnet, nämlich der Elementtyp des Indexers.Every indexer access has an associated type, namely the element type of the indexer. Außerdem verfügt ein Indexer-Zugriff über einen zugeordneten Instanzausdruck und eine zugeordnete Argumentliste.Furthermore, an indexer access has an associated instance expression and an associated argument list. Wenn ein Accessor (der- get oder- set Block) eines Indexerzugriffs aufgerufen wird, wird das Ergebnis der Auswertung des Instanzausdrucks zu der durch dargestellten Instanz this (dieser Zugriff), und das Ergebnis der Auswertung der Argumentliste wird zur Parameterliste des aufzurufenden aufzurufenden.When an accessor (the get or set block) of an indexer access is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access), and the result of evaluating the argument list becomes the parameter list of the invocation.
  • Nichts.Nothing. Dies tritt auf, wenn der Ausdruck ein Aufruf einer Methode mit dem Rückgabetyp ist void .This occurs when the expression is an invocation of a method with a return type of void. Ein Ausdruck, der als Nothing klassifiziert ist, ist nur im Kontext einer statement_expression (Ausdrucks Anweisungen) gültig.An expression classified as nothing is only valid in the context of a statement_expression (Expression statements).

Das Endergebnis eines Ausdrucks ist nie ein Namespace, ein Typ, eine Methoden Gruppe oder ein Ereignis Zugriff.The final result of an expression is never a namespace, type, method group, or event access. Wie oben bereits erwähnt, sind diese Kategorien von Ausdrücken zwischenkonstrukte, die nur in bestimmten Kontexten zulässig sind.Rather, as noted above, these categories of expressions are intermediate constructs that are only permitted in certain contexts.

Ein Eigenschaften Zugriff oder Indexer-Zugriff wird immer als Wert neu klassifiziert, indem ein Aufruf des Get-Accessor oder des set-Accessors ausgeführt wird.A property access or indexer access is always reclassified as a value by performing an invocation of the get accessor or the set accessor. Der jeweilige Accessor wird durch den Kontext der Eigenschaft oder des Indexerzugriffs bestimmt: Wenn der Zugriff das Ziel einer Zuweisung ist, wird der Set-Accessor aufgerufen, um einen neuen Wert zuzuweisen (einfache Zuweisung).The particular accessor is determined by the context of the property or indexer access: If the access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). Andernfalls wird der Get-Accessor aufgerufen, um den aktuellen Wert zu erhalten (Werte von Ausdrücken).Otherwise, the get accessor is invoked to obtain the current value (Values of expressions).

Werte von AusdrückenValues of expressions

Die meisten Konstrukte, die einen Ausdruck einschließen, erfordern letztendlich, dass der Ausdruck einen Wert angibt.Most of the constructs that involve an expression ultimately require the expression to denote a value. In solchen Fällen tritt ein Kompilierzeitfehler auf, wenn der tatsächliche Ausdruck einen Namespace, einen Typ, eine Methoden Gruppe oder nichts angibt.In such cases, if the actual expression denotes a namespace, a type, a method group, or nothing, a compile-time error occurs. Wenn der Ausdruck jedoch einen Eigenschaften Zugriff, einen Indexer-Zugriff oder eine Variable angibt, wird der Wert der Eigenschaft, des Indexers oder der Variablen implizit ersetzt:However, if the expression denotes a property access, an indexer access, or a variable, the value of the property, indexer, or variable is implicitly substituted:

  • Der Wert einer Variablen ist einfach der Wert, der zurzeit an dem von der Variablen identifizierten Speicherort gespeichert ist.The value of a variable is simply the value currently stored in the storage location identified by the variable. Eine Variable muss als definitiv zugewiesen (definitive Zuweisung) betrachtet werden, bevor ihr Wert abgerufen werden kann. andernfalls tritt ein Kompilierzeitfehler auf.A variable must be considered definitely assigned (Definite assignment) before its value can be obtained, or otherwise a compile-time error occurs.
  • Der Wert eines Eigenschafts Zugriffs Ausdrucks wird abgerufen, indem der Get-Accessor der Eigenschaft aufgerufen wird.The value of a property access expression is obtained by invoking the get accessor of the property. Wenn die Eigenschaft keinen Get-Accessor aufweist, tritt ein Kompilierzeitfehler auf.If the property has no get accessor, a compile-time error occurs. Andernfalls wird ein Funktionsmember-Aufruf (Kompilierzeit Überprüfung der dynamischen Überladungs Auflösung) ausgeführt, und das Ergebnis des aufzurufenden Ausdrucks wird zum Wert des Eigenschafts Zugriffs Ausdrucks.Otherwise, a function member invocation (Compile-time checking of dynamic overload resolution) is performed, and the result of the invocation becomes the value of the property access expression.
  • Der Wert eines indexerzugriffsausdrucks wird abgerufen, indem der Get-Accessor des Indexers aufgerufen wird.The value of an indexer access expression is obtained by invoking the get accessor of the indexer. Wenn der Indexer keinen Get-Accessor aufweist, tritt ein Kompilierzeitfehler auf.If the indexer has no get accessor, a compile-time error occurs. Andernfalls wird ein Funktionsmember-Aufruf (Kompilierzeit Überprüfung der dynamischen Überladungs Auflösung) mit der Argumentliste ausgeführt, die dem indexerzugriffsausdruck zugeordnet ist, und das Ergebnis des aufzurufenden Ausdrucks wird zum Wert des Zugriffs Ausdrucks des Indexers.Otherwise, a function member invocation (Compile-time checking of dynamic overload resolution) is performed with the argument list associated with the indexer access expression, and the result of the invocation becomes the value of the indexer access expression.

Static and Dynamic Binding (Statische und dynamische Bindung)Static and Dynamic Binding

Der Prozess der Bestimmung der Bedeutung eines Vorgangs basierend auf dem Typ oder Wert von konstituierenden Ausdrücken (Argumente, Operanden, Empfänger) wird häufig als Bindung bezeichnet.The process of determining the meaning of an operation based on the type or value of constituent expressions (arguments, operands, receivers) is often referred to as binding. Zum Beispiel wird die Bedeutung eines Methoden Aufrufes basierend auf dem Typ des Empfängers und der Argumente bestimmt.For instance the meaning of a method call is determined based on the type of the receiver and arguments. Die Bedeutung eines Operators wird basierend auf dem Typ seiner Operanden bestimmt.The meaning of an operator is determined based on the type of its operands.

In c# wird die Bedeutung eines Vorgangs in der Regel zur Kompilierzeit bestimmt, basierend auf dem Kompilier Zeittyp der enthaltenen Ausdrücke.In C# the meaning of an operation is usually determined at compile-time, based on the compile-time type of its constituent expressions. Wenn ein Ausdruck einen Fehler enthält, wird der Fehler auch vom Compiler erkannt und gemeldet.Likewise, if an expression contains an error, the error is detected and reported by the compiler. Diese Vorgehensweise wird als statische Bindung bezeichnet.This approach is known as static binding.

Wenn ein Ausdruck jedoch ein dynamischer Ausdruck ist (d. h. den-Typ aufweist dynamic ), gibt dies an, dass jede Bindung, an der Sie teilnimmt, auf dem Lauf Zeittyp (d. h. dem tatsächlichen Typ des Objekts, das Sie zur Laufzeit bezeichnet) und nicht auf dem Typ, der zur Kompilierzeit vorhanden ist, basieren soll.However, if an expression is a dynamic expression (i.e. has the type dynamic) this indicates that any binding that it participates in should be based on its run-time type (i.e. the actual type of the object it denotes at run-time) rather than the type it has at compile-time. Die Bindung eines solchen Vorgangs wird daher bis zu der Zeit verzögert, in der der Vorgang während der Ausführung des Programms ausgeführt werden soll.The binding of such an operation is therefore deferred until the time where the operation is to be executed during the running of the program. Dies wird als dynamische Bindung bezeichnet.This is referred to as dynamic binding.

Wenn ein Vorgang dynamisch gebunden ist, wird vom Compiler nur eine kleine oder keine Überprüfung durchgeführt.When an operation is dynamically bound, little or no checking is performed by the compiler. Wenn die Lauf Zeitbindung fehlschlägt, werden Fehler zur Laufzeit als Ausnahmen gemeldet.Instead if the run-time binding fails, errors are reported as exceptions at run-time.

Die folgenden Vorgänge in c# unterliegen der Bindung:The following operations in C# are subject to binding:

  • Mitgliederzugriff: e.MMember access: e.M
  • Methodenaufruf: e.M(e1, ..., eN)Method invocation: e.M(e1, ..., eN)
  • Delegataufruf:e(e1, ..., eN)Delegate invocation:e(e1, ..., eN)
  • Element Zugriff: e[e1, ..., eN]Element access: e[e1, ..., eN]
  • Objekt Erstellung: new C(e1, ..., eN)Object creation: new C(e1, ..., eN)
  • Überladene unäre Operatoren: + , - , ! , ~ , ++ , -- , true , falseOverloaded unary operators: +, -, !, ~, ++, --, true, false
  • Überladene binäre Operatoren: + , - , * , / , % , & , && , | , || , ?? , ^ , << , >> , == , != , > , < , >= , <=Overloaded binary operators: +, -, *, /, %, &, &&, |, ||, ??, ^, <<, >>, ==,!=, >, <, >=, <=
  • Zuweisungs Operatoren: = , += , -= , *= , /= , %= , &= , |= , ^= , <<= , >>=Assignment operators: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
  • Implizite und explizite KonvertierungenImplicit and explicit conversions

Wenn keine dynamischen Ausdrücke beteiligt sind, wird in c# standardmäßig die statische Bindung verwendet. Dies bedeutet, dass die Kompilierzeit Typen von konstituierenden Ausdrücken im Auswahl Vorgang verwendet werden.When no dynamic expressions are involved, C# defaults to static binding, which means that the compile-time types of constituent expressions are used in the selection process. Wenn jedoch einer der in den oben aufgeführten Vorgängen aufgeführten Ausdrücke ein dynamischer Ausdruck ist, wird der Vorgang stattdessen dynamisch gebunden.However, when one of the constituent expressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound.

Bindungs ZeitBinding-time

Die statische Bindung erfolgt zur Kompilierzeit, während die dynamische Bindung zur Laufzeit stattfindet.Static binding takes place at compile-time, whereas dynamic binding takes place at run-time. In den folgenden Abschnitten bezieht sich der Begriff " Bindungs Zeit " entweder auf die Kompilierzeit oder die Laufzeit, je nachdem, wann die Bindung stattfindet.In the following sections, the term binding-time refers to either compile-time or run-time, depending on when the binding takes place.

Das folgende Beispiel veranschaulicht die Begriffe der statischen und dynamischen Bindung und der Bindungs Zeit:The following example illustrates the notions of static and dynamic binding and of binding-time:

object  o = 5;
dynamic d = 5;

Console.WriteLine(5);  // static  binding to Console.WriteLine(int)
Console.WriteLine(o);  // static  binding to Console.WriteLine(object)
Console.WriteLine(d);  // dynamic binding to Console.WriteLine(int)

Die ersten beiden Aufrufe sind statisch gebunden: die Überladung von Console.WriteLine wird basierend auf dem Kompilier Zeittyp ihres Arguments ausgewählt.The first two calls are statically bound: the overload of Console.WriteLine is picked based on the compile-time type of their argument. Folglich ist die Bindungs Zeit die Kompilierzeit.Thus, the binding-time is compile-time.

Der dritte Aufruf ist dynamisch gebunden: die Überladung von Console.WriteLine wird basierend auf dem Lauf Zeittyp des Arguments ausgewählt.The third call is dynamically bound: the overload of Console.WriteLine is picked based on the run-time type of its argument. Dies liegt daran, dass das-Argument ein dynamischer Ausdruck ist, der Kompilier Zeittyp ist dynamic .This happens because the argument is a dynamic expression -- its compile-time type is dynamic. Folglich ist die Bindungs Zeit für den dritten Aufruf Lauf Zeit.Thus, the binding-time for the third call is run-time.

Dynamische BindungDynamic binding

Der Zweck der dynamischen Bindung besteht darin, dass c#-Programme mit dynamischen Objekten interagieren können, d. h. Objekte, die nicht den normalen Regeln des c#-Typsystems entsprechen.The purpose of dynamic binding is to allow C# programs to interact with dynamic objects, i.e. objects that do not follow the normal rules of the C# type system. Dynamische Objekte können Objekte aus anderen Programmiersprachen mit unterschiedlichen Typen Systemen sein, oder es handelt sich um Objekte, die Programm gesteuert eingerichtet werden, um Ihre eigene Bindungs Semantik für verschiedene Vorgänge zu implementieren.Dynamic objects may be objects from other programming languages with different types systems, or they may be objects that are programmatically setup to implement their own binding semantics for different operations.

Der Mechanismus, mit dem ein dynamisches Objekt seine eigene Semantik implementiert, ist die Implementierung definiert.The mechanism by which a dynamic object implements its own semantics is implementation defined. Eine bestimmte Schnittstelle, die wieder implementiert wird, wird von dynamischen Objekten implementiert, um der c#-Laufzeit zu signalisieren, dass Sie über eine besondere Semantik verfügen.A given interface -- again implementation defined -- is implemented by dynamic objects to signal to the C# run-time that they have special semantics. Wenn also Vorgänge für ein dynamisches Objekt dynamisch gebunden werden, übernehmen Sie die eigene Bindungs Semantik anstelle von c#-Daten, die in diesem Dokument angegeben sind.Thus, whenever operations on a dynamic object are dynamically bound, their own binding semantics, rather than those of C# as specified in this document, take over.

Der Zweck der dynamischen Bindung besteht darin, die Interoperabilität mit dynamischen Objekten zuzulassen, aber c# ermöglicht die dynamische Bindung für alle Objekte, unabhängig davon, ob Sie dynamisch sind oder nicht.While the purpose of dynamic binding is to allow interoperation with dynamic objects, C# allows dynamic binding on all objects, whether they are dynamic or not. Dies ermöglicht eine reibungslosere Integration dynamischer Objekte, da die Ergebnisse von Vorgängen für diese nicht selbst dynamische Objekte sein können, aber immer noch ein Typ ist, der dem Programmierer zur Kompilierzeit unbekannt ist.This allows for a smoother integration of dynamic objects, as the results of operations on them may not themselves be dynamic objects, but are still of a type unknown to the programmer at compile-time. Außerdem kann die dynamische Bindung helfen, fehleranfälligen reflektionsbasierten Code zu eliminieren, auch wenn keine Objekte an dynamischen Objekten beteiligt sind.Also dynamic binding can help eliminate error-prone reflection-based code even when no objects involved are dynamic objects.

In den folgenden Abschnitten wird für jedes Konstrukt in der Sprache exakt beschrieben, wann die dynamische Bindung angewendet wird, welche Kompilierzeit Überprüfung (sofern vorhanden) angewendet wird und wie das Ergebnis und die Ausdrucks Klassifizierung der Kompilierung ist.The following sections describe for each construct in the language exactly when dynamic binding is applied, what compile time checking -- if any -- is applied, and what the compile-time result and expression classification is.

Typen von konstituierenden AusdrückenTypes of constituent expressions

Wenn ein Vorgang statisch gebunden ist, wird der Typ eines einzelnen Ausdrucks (z. b. ein Empfänger, ein Argument, ein Index oder ein Operand) immer als der Kompilier Zeittyp dieses Ausdrucks betrachtet.When an operation is statically bound, the type of a constituent expression (e.g. a receiver, an argument, an index or an operand) is always considered to be the compile-time type of that expression.

Wenn ein Vorgang dynamisch gebunden wird, wird der Typ eines einzelnen Ausdrucks basierend auf dem Kompilier Zeittyp des konstituierenden Ausdrucks auf unterschiedliche Weise bestimmt:When an operation is dynamically bound, the type of a constituent expression is determined in different ways depending on the compile-time type of the constituent expression:

  • Ein konstituierender Ausdruck des Kompilierzeit Typs dynamic wird als der Typ des tatsächlichen Werts betrachtet, zu dem der Ausdruck zur Laufzeit ausgewertet wird.A constituent expression of compile-time type dynamic is considered to have the type of the actual value that the expression evaluates to at runtime
  • Ein konstituierender Ausdruck, dessen Kompilier Zeittyp ein Typparameter ist, wird als Typ betrachtet, an den der Typparameter zur Laufzeit gebunden ist.A constituent expression whose compile-time type is a type parameter is considered to have the type which the type parameter is bound to at runtime
  • Andernfalls wird der entsprechende Kompilier Zeittyp für den enthaltenen Ausdruck berücksichtigt.Otherwise the constituent expression is considered to have its compile-time type.

OperatorenOperators

Ausdrücke werden aus Operanden _-und- _Operatoren*_ erstellt.Expressions are constructed from operands _ and _operators*_. Die Operatoren eines Ausdrucks geben an, welche Operationen auf die Operanden angewendet werden.The operators of an expression indicate which operations to apply to the operands. Beispiele für Operatoren sind +, -, _, / und new.Examples of operators include +, -, _, /, and new. Beispiele für Operanden sind Literale, Felder, lokale Variablen und Ausdrücke.Examples of operands include literals, fields, local variables, and expressions.

Es gibt drei Arten von Operatoren:There are three kinds of operators:

  • Unäre Operatoren.Unary operators. Die unären Operatoren nehmen einen Operanden an und verwenden entweder eine Präfix Notation (z. b. --x ) oder eine Postfix Notation (z x++ . b.).The unary operators take one operand and use either prefix notation (such as --x) or postfix notation (such as x++).
  • Binäre Operatoren.Binary operators. Die binären Operatoren nehmen zwei Operanden an und verwenden die Infix-Notation (z x + y . b.).The binary operators take two operands and all use infix notation (such as x + y).
  • Ternärer Operator.Ternary operator. Nur ein ternärer Operator, ?: , ist vorhanden; er nimmt drei Operanden an und verwendet die Infix-Notation ( c ? x : y ).Only one ternary operator, ?:, exists; it takes three operands and uses infix notation (c ? x : y).

Die Reihenfolge der Auswertung von Operatoren in einem Ausdruck wird durch die * Rang Folge _ und _ Assoziativität* der Operatoren (Operator Rangfolge und Assoziativität) bestimmt.The order of evaluation of operators in an expression is determined by the precedence _ and _ associativity of the operators (Operator precedence and associativity).

Operanden in einem Ausdruck werden von links nach rechts ausgewertet.Operands in an expression are evaluated from left to right. In wird die-Methode z. b. mit F(i) + G(i++) * H(i) F dem alten Wert von aufgerufen. i anschließend G wird die-Methode mit dem alten Wert von aufgerufen, i und schließlich H wird die-Methode mit dem neuen Wert von aufgerufen i .For example, in F(i) + G(i++) * H(i), method F is called using the old value of i, then method G is called with the old value of i, and, finally, method H is called with the new value of i. Dies ist getrennt von und nicht mit der Operator Rangfolge.This is separate from and unrelated to operator precedence.

Bestimmte Operatoren können überladen werden.Certain operators can be overloaded. Die Operator Überladung ermöglicht das Angeben von benutzerdefinierten Operator Implementierungen für Vorgänge, bei denen einer oder beide der Operanden eine benutzerdefinierte Klasse oder ein Strukturtyp sind (Operator Überladung).Operator overloading permits user-defined operator implementations to be specified for operations where one or both of the operands are of a user-defined class or struct type (Operator overloading).

Operatorrangfolge und AssoziativitätOperator precedence and associativity

Wenn ein Ausdruck mehrere Operatoren enthält, steuert die *Rangfolge _ der Operatoren die Reihenfolge, in der die einzelnen Operatoren ausgewertet werden.When an expression contains multiple operators, the *precedence _ of the operators controls the order in which the individual operators are evaluated. Beispielsweise wird der Ausdruck x + y _ z als x + (y * z) ausgewertet, da der *-Operator eine höhere Rangfolge aufweist als der binäre +-Operator.For example, the expression x + y _ z is evaluated as x + (y * z) because the * operator has higher precedence than the binary + operator. Die Rangfolge eines Operators wird durch die Definition der zugehörigen Grammatikproduktion festgelegt.The precedence of an operator is established by the definition of its associated grammar production. Ein additive_expression besteht z. b. aus einer Sequenz von multiplicative_expression s, die durch + or- - Operatoren getrennt sind, sodass der + -Operator und der- - Operator eine niedrigere Rangfolge als die * / % Operatoren, undFor example, an additive_expression consists of a sequence of multiplicative_expression s separated by + or - operators, thus giving the + and - operators lower precedence than the *, /, and % operators.

In der folgenden Tabelle werden alle Operatoren in der Rangfolge von der höchsten zur niedrigsten aufgeführt:The following table summarizes all operators in order of precedence from highest to lowest:

BereichSection KategorieCategory OperatorenOperators
Primäre AusdrückePrimary expressions PrimärPrimary x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegatex.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate
Unäre OperatorenUnary operators UnärUnary + - ! ~ ++x --x (T)x+ - ! ~ ++x --x (T)x
Arithmetic operators (Arithmetische Operatoren)Arithmetic operators MultiplikativMultiplicative * / %* / %
Arithmetic operators (Arithmetische Operatoren)Arithmetic operators AdditivAdditive + -+ -
Shift operators (Schiebeoperatoren)Shift operators ShiftShift << >><< >>
Relationale und Typtest OperatorenRelational and type-testing operators Relational und TyptestRelational and type testing < > <= >= is as< > <= >= is as
Relationale und Typtest OperatorenRelational and type-testing operators GleichheitEquality == !=== !=
Logische OperatorenLogical operators Logisches ANDLogical AND &
Logische OperatorenLogical operators Logisches XORLogical XOR ^
Logische OperatorenLogical operators Logisches ORLogical OR |
Conditional logical operators (Bedingte logische Operatoren)Conditional logical operators Bedingtes ANDConditional AND &&
Conditional logical operators (Bedingte logische Operatoren)Conditional logical operators Bedingtes ORConditional OR ||
The null coalescing operator (Der NULL-Sammeloperator)The null coalescing operator NULL-SammeloperatorNull coalescing ??
Bedingter OperatorConditional operator BedingtConditional ?:
Zuweisungs Operatoren, Anonyme Funktions AusdrückeAssignment operators, Anonymous function expressions Zuweisungs- und Lambda-AusdrückeAssignment and lambda expression = *= /= %= += -= <<= >>= &= ^= |= =>= *= /= %= += -= <<= >>= &= ^= |= =>

Tritt ein Operand zwischen zwei Operatoren mit gleicher Rangfolge auf, steuert die Assoziativität der Operatoren die Reihenfolge, in der die Vorgänge ausgeführt werden:When an operand occurs between two operators with the same precedence, the associativity of the operators controls the order in which the operations are performed:

  • Mit Ausnahme der Zuweisungs Operatoren und des NULL-Sammel Operators sind alle binären Operatoren Links bündig. Dies bedeutet, dass Vorgänge von links nach rechts ausgeführt werden.Except for the assignment operators and the null coalescing operator, all binary operators are left-associative, meaning that operations are performed from left to right. x + y + z wird beispielsweise als (x + y) + z ausgewertet.For example, x + y + z is evaluated as (x + y) + z.
  • Die Zuweisungs Operatoren, der NULL-Sammel Operator und der bedingte Operator ( ?: ) sind Rechts assoziativ, was bedeutet, dass Vorgänge von rechts nach links ausgeführt werden.The assignment operators, the null coalescing operator and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. x = y = z wird beispielsweise als x = (y = z) ausgewertet.For example, x = y = z is evaluated as x = (y = z).

Rangfolge und Assoziativität können mit Klammern gesteuert werden.Precedence and associativity can be controlled using parentheses. In x + y * z wird beispielsweise zuerst y mit z multipliziert und dann das Ergebnis zu x addiert, aber in (x + y) * z werden zunächst x und y addiert, und dann wird das Ergebnis mit z multipliziert.For example, x + y * z first multiplies y by z and then adds the result to x, but (x + y) * z first adds x and y and then multiplies the result by z.

Überladen von OperatorenOperator overloading

Alle unären und binären Operatoren verfügen über vordefinierte Implementierungen, die automatisch in jedem Ausdruck verfügbar sind.All unary and binary operators have predefined implementations that are automatically available in any expression. Zusätzlich zu den vordefinierten Implementierungen können benutzerdefinierte Implementierungen durch Einschließen von operator Deklarationen in Klassen und Strukturen (Operatoren) eingeführt werden.In addition to the predefined implementations, user-defined implementations can be introduced by including operator declarations in classes and structs (Operators). Implementierungen von benutzerdefinierten Operatoren haben immer Vorrang vor vordefinierten Operator Implementierungen: nur wenn keine anwendbaren benutzerdefinierten Operator Implementierungen vorhanden sind, werden die vordefinierten Operator Implementierungen in Erwägung gezogen, wie unter unäre Operator Überladungs Auflösung und binäre Operator Überladungs Auflösungbeschrieben.User-defined operator implementations always take precedence over predefined operator implementations: Only when no applicable user-defined operator implementations exist will the predefined operator implementations be considered, as described in Unary operator overload resolution and Binary operator overload resolution.

Die über ladbaren unären Operatoren sind:The overloadable unary operators are:

+   -   !   ~   ++   --   true   false

Obwohl true und false nicht explizit in Ausdrücken verwendet werden (und daher nicht in der Rang folgen Tabelle in der Operator Rangfolge und Assoziativitätenthalten sind), werden Sie als Operatoren angesehen, da Sie in mehreren Ausdrucks Kontexten aufgerufen werden: boolesche Ausdrücke (boolesche Ausdrücke) und Ausdrücke mit bedingtem (bedingtem Operator) und bedingten logischen Operatoren (bedingte logische Operatoren).Although true and false are not used explicitly in expressions (and therefore are not included in the precedence table in Operator precedence and associativity), they are considered operators because they are invoked in several expression contexts: boolean expressions (Boolean expressions) and expressions involving the conditional (Conditional operator), and conditional logical operators (Conditional logical operators).

Die über ladbaren binären Operatoren sind:The overloadable binary operators are:

+   -   *   /   %   &   |   ^   <<   >>   ==   !=   >   <   >=   <=

Nur die oben aufgeführten Operatoren können überladen werden.Only the operators listed above can be overloaded. Insbesondere ist es nicht möglich, Element Zugriffe, Methodenaufrufe oder die = && || Operatoren,,,, ?? ?: , => , checked , unchecked ,,, new typeof default , as und is zu überladen.In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, as, and is operators.

Wenn ein binärer Operator überladen ist, wird der zugehörige Zuweisungsoperator, sofern er vorhanden ist, auch implizit überladen.When a binary operator is overloaded, the corresponding assignment operator, if any, is also implicitly overloaded. Beispielsweise ist eine Überladung des-Operators * auch eine Überladung des-Operators *= .For example, an overload of operator * is also an overload of operator *=. Dies wird in der Verbund Zuweisungweiter unten beschrieben.This is described further in Compound assignment. Beachten Sie, dass der Zuweisungs Operator selbst ( = ) nicht überladen werden kann.Note that the assignment operator itself (=) cannot be overloaded. Eine Zuweisung führt immer eine einfache bitweise Kopie eines Werts in eine Variable aus.An assignment always performs a simple bit-wise copy of a value into a variable.

Umwandlungs Vorgänge, wie z (T)x . b., werden durch die Bereitstellung von benutzerdefinierten Konvertierungen (benutzerdefinierte Konvertierungen) überladen.Cast operations, such as (T)x, are overloaded by providing user-defined conversions (User-defined conversions).

Der Element Zugriff, z a[x] . b., wird nicht als über ladbarer Operator angesehen.Element access, such as a[x], is not considered an overloadable operator. Stattdessen wird die benutzerdefinierte Indizierung durch Indexer (Indexer) unterstützt.Instead, user-defined indexing is supported through indexers (Indexers).

In Ausdrücken wird mithilfe der Operator Notation auf Operatoren verwiesen, und in Deklarationen wird auf Operatoren mithilfe der funktionalen Notation verwiesen.In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. In der folgenden Tabelle wird die Beziehung zwischen Operator-und Funktions Notizen für unäre und binäre Operatoren veranschaulicht.The following table shows the relationship between operator and functional notations for unary and binary operators. Im ersten Eintrag bezeichnet op alle über ladbaren unären Präfix Operatoren.In the first entry, op denotes any overloadable unary prefix operator. Im zweiten Eintrag bezeichnet op die unären postfix ++ -und- -- Operatoren.In the second entry, op denotes the unary postfix ++ and -- operators. Im dritten Eintrag bezeichnet op jeden über ladbaren binären Operator.In the third entry, op denotes any overloadable binary operator.

Operator NotationOperator notation Funktionale NotationFunctional notation
op x operator op(x)
x op operator op(x)
x op y operator op(x,y)

Benutzerdefinierte Operator Deklarationen erfordern immer, dass mindestens einer der Parameter vom Klassen-oder Strukturtyp ist, der die Operator Deklaration enthält.User-defined operator declarations always require at least one of the parameters to be of the class or struct type that contains the operator declaration. Daher ist es nicht möglich, dass ein benutzerdefinierter Operator dieselbe Signatur wie ein vordefinierter Operator hat.Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.

Benutzerdefinierte Operator Deklarationen können die Syntax, Rangfolge oder Assoziativität eines Operators nicht ändern.User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. Beispielsweise ist der- / Operator immer ein binärer Operator, verfügt immer über die in Operator Rangfolge und Assoziativitätangegebene Rang folgen Ebene und ist immer links assoziativ.For example, the / operator is always a binary operator, always has the precedence level specified in Operator precedence and associativity, and is always left-associative.

Obwohl es möglich ist, dass ein benutzerdefinierter Operator jede beliebige Berechnung durchführt, wird dringend davon abgeraten, Implementierungen, die andere Ergebnisse als diejenigen ergeben, die intuitiv erwartet werden.While it is possible for a user-defined operator to perform any computation it pleases, implementations that produce results other than those that are intuitively expected are strongly discouraged. Beispielsweise sollte eine Implementierung von operator == die beiden Operanden auf Gleichheit vergleichen und ein entsprechendes Ergebnis zurückgeben bool .For example, an implementation of operator == should compare the two operands for equality and return an appropriate bool result.

Die Beschreibungen der einzelnen Operatoren in Primary Expressions durch bedingte logische Operatoren geben die vordefinierten Implementierungen der Operatoren sowie alle zusätzlichen Regeln an, die für die einzelnen Operatoren gelten.The descriptions of individual operators in Primary expressions through Conditional logical operators specify the predefined implementations of the operators and any additional rules that apply to each operator. Die Beschreibungen verwenden die Begriffe unäre Operator Überladungs Auflösung _, _binäre Operator Überladungs Auflösung*_ und _ *numerische herauf Stufung * *, Definitionen von, die in den folgenden Abschnitten zu finden sind.The descriptions make use of the terms unary operator overload resolution _, _binary operator overload resolution_, and _numeric promotion**, definitions of which are found in the following sections.

Überladungs Auflösung für unären OperatorUnary operator overload resolution

Ein Vorgang des Formulars op x oder x op , wobei op ein über ladbarer unärer Operator ist und x ein Ausdruck vom Typ ist X , wird wie folgt verarbeitet:An operation of the form op x or x op, where op is an overloadable unary operator, and x is an expression of type X, is processed as follows:

  • Der Satz von benutzerdefinierten Operatoren, die von X für den Vorgang bereitgestellt werden, operator op(x) wird mithilfe der Regeln von benutzerdefinierten Operatoren des Kandidatenbestimmt.The set of candidate user-defined operators provided by X for the operation operator op(x) is determined using the rules of Candidate user-defined operators.
  • Wenn der Satz von benutzerdefinierten Operatoren des Kandidaten nicht leer ist, wird dies zur Gruppe der Kandidaten Operatoren für den Vorgang.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Andernfalls werden die vordefinierten unären operator op Implementierungen, einschließlich ihrer angehobenen Formulare, zur Gruppe der Kandidaten Operatoren für den Vorgang.Otherwise, the predefined unary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Die vordefinierten Implementierungen eines angegebenen Operators werden in der Beschreibung des Operators (primär Ausdrücke und unäre Operatoren) angegeben.The predefined implementations of a given operator are specified in the description of the operator (Primary expressions and Unary operators).
  • Die Regeln für die Überladungs Auflösung der Überladungs Auflösung werden auf den Satz von Kandidaten Operatoren angewendet, um den besten Operator in Bezug auf die Argumentliste auszuwählen (x) , und dieser Operator wird zum Ergebnis der Überladungs Auflösung.The overload resolution rules of Overload resolution are applied to the set of candidate operators to select the best operator with respect to the argument list (x), and this operator becomes the result of the overload resolution process. Wenn bei der Überladungs Auflösung nicht der einzige beste Operator ausgewählt werden kann, tritt ein Bindungs Zeitfehler auf.If overload resolution fails to select a single best operator, a binding-time error occurs.

Binäre Operator Überladungs AuflösungBinary operator overload resolution

Ein Vorgang in der Form x op y , wobei op ein über ladbarer binärer Operator ist, x ein Ausdruck vom Typ X und y ein Ausdruck vom Typ ist Y , wird wie folgt verarbeitet:An operation of the form x op y, where op is an overloadable binary operator, x is an expression of type X, and y is an expression of type Y, is processed as follows:

  • Der Satz von benutzerdefinierten Operatoren, die von X und für den-Vorgang bereitgestellt werden, Y operator op(x,y) wird bestimmt.The set of candidate user-defined operators provided by X and Y for the operation operator op(x,y) is determined. Der Satz besteht aus der Vereinigung der Kandidaten Operatoren, die von bereitgestellt werden X , und der von bereitgestellten Kandidaten Operatoren Y , die jeweils mithilfe der Regeln von benutzerdefinierten Operatoren des Kandidatenbestimmt werden.The set consists of the union of the candidate operators provided by X and the candidate operators provided by Y, each determined using the rules of Candidate user-defined operators. Wenn X und Y denselben Typ haben oder wenn X und Y von einem gemeinsamen Basistyp abgeleitet sind, treten freigegebene Kandidaten Operatoren nur einmal in der kombinierten Menge auf.If X and Y are the same type, or if X and Y are derived from a common base type, then shared candidate operators only occur in the combined set once.
  • Wenn der Satz von benutzerdefinierten Operatoren des Kandidaten nicht leer ist, wird dies zur Gruppe der Kandidaten Operatoren für den Vorgang.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Andernfalls werden die vordefinierten binären operator op Implementierungen, einschließlich ihrer angehobenen Formulare, zur Gruppe der Kandidaten Operatoren für den Vorgang.Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Die vordefinierten Implementierungen eines angegebenen Operators werden in der Beschreibung des Operators (arithmetische Operatoren durch bedingte logische Operatoren) angegeben.The predefined implementations of a given operator are specified in the description of the operator (Arithmetic operators through Conditional logical operators). Bei vordefinierten Aufzählungs-und delegatoperatoren sind die einzigen Operatoren, die von einem Aufzählungs-oder Delegattyp definiert werden, der der Bindungstyp von einem der Operanden ist.For predefined enum and delegate operators, the only operators considered are those defined by an enum or delegate type that is the binding-time type of one of the operands.
  • Die Regeln für die Überladungs Auflösung der Überladungs Auflösung werden auf den Satz von Kandidaten Operatoren angewendet, um den besten Operator in Bezug auf die Argumentliste auszuwählen (x,y) , und dieser Operator wird zum Ergebnis der Überladungs Auflösung.The overload resolution rules of Overload resolution are applied to the set of candidate operators to select the best operator with respect to the argument list (x,y), and this operator becomes the result of the overload resolution process. Wenn bei der Überladungs Auflösung nicht der einzige beste Operator ausgewählt werden kann, tritt ein Bindungs Zeitfehler auf.If overload resolution fails to select a single best operator, a binding-time error occurs.

Benutzerdefinierte Operatoren für KandidatenCandidate user-defined operators

Bei einem Typ T und einem Vorgang operator op(A) , bei dem op es sich um einen über ladbaren Operator handelt und A es sich um eine Argumentliste handelt, wird der von for bereitgestellte Satz von benutzerdefinierten Operatoren T operator op(A) wie folgt bestimmt:Given a type T and an operation operator op(A), where op is an overloadable operator and A is an argument list, the set of candidate user-defined operators provided by T for operator op(A) is determined as follows:

  • Bestimmen Sie den Typ T0 .Determine the type T0. Wenn T ein Typ ist, der NULL-Werte zulässt, T0 ist der zugrunde liegende Typ, andernfalls T0 ist gleich T .If T is a nullable type, T0 is its underlying type, otherwise T0 is equal to T.
  • Bei allen operator op Deklarationen in T0 und allen aufgelegten Formen solcher Operatoren, wenn mindestens ein Operator anwendbar ist (anwendbarer Funktionsmember), der sich auf die Argumentliste betrifft A , besteht der Satz von Kandidaten Operatoren aus allen anwendbaren Operatoren in T0 .For all operator op declarations in T0 and all lifted forms of such operators, if at least one operator is applicable (Applicable function member) with respect to the argument list A, then the set of candidate operators consists of all such applicable operators in T0.
  • Andernfalls T0 object ist der Satz von Kandidaten Operatoren leer, wenn ist.Otherwise, if T0 is object, the set of candidate operators is empty.
  • Andernfalls ist der Satz von Kandidaten Operatoren, der von bereitgestellt T0 wird, der Satz von Kandidaten Operatoren, der von der direkten Basisklasse von bereitgestellt wird T0 , oder die effektive Basisklasse von, T0 Wenn T0 ein Typparameter ist.Otherwise, the set of candidate operators provided by T0 is the set of candidate operators provided by the direct base class of T0, or the effective base class of T0 if T0 is a type parameter.

Numerische HeraufstufungenNumeric promotions

Die numerische herauf Stufung besteht aus dem automatischen Ausführen bestimmter impliziter Konvertierungen der Operanden der vordefinierten unären und binären numerischen Operatoren.Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. Die numerische herauf Stufung ist kein eindeutiger Mechanismus, sondern wirkt sich eher auf die Anwendung der Überladungs Auflösung auf die vordefinierten Operatoren aus.Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. Die numerische herauf Stufung wirkt sich nicht auf die Auswertung von benutzerdefinierten Operatoren aus, obwohl benutzerdefinierte Operatoren implementiert werden können, um ähnliche Effekte zu erzeugen.Numeric promotion specifically does not affect evaluation of user-defined operators, although user-defined operators can be implemented to exhibit similar effects.

Sehen Sie sich als Beispiel für die numerische herauf Stufung die vordefinierten Implementierungen des binären * Operators an:As an example of numeric promotion, consider the predefined implementations of the binary * operator:

int operator *(int x, int y);
uint operator *(uint x, uint y);
long operator *(long x, long y);
ulong operator *(ulong x, ulong y);
float operator *(float x, float y);
double operator *(double x, double y);
decimal operator *(decimal x, decimal y);

Wenn Regeln zur Überladungs Auflösung (ÜberladungsAuflösung) auf diese Gruppe von Operatoren angewendet werden, besteht der Effekt darin, den ersten Operator auszuwählen, für den implizite Konvertierungen aus den Operanden Typen vorhanden sind.When overload resolution rules (Overload resolution) are applied to this set of operators, the effect is to select the first of the operators for which implicit conversions exist from the operand types. Für den b * s -Vorgang, bei dem b ein byte und s ein ist short , wählt die Überladungs Auflösung beispielsweise operator *(int,int) als besten Operator aus.For example, for the operation b * s, where b is a byte and s is a short, overload resolution selects operator *(int,int) as the best operator. Folglich ist der Effekt, dass b und s in konvertiert werden int , und der Ergebnistyp ist int .Thus, the effect is that b and s are converted to int, and the type of the result is int. Entsprechend i * d wählt die Überladungs Auflösung für den-Vorgang, bei dem i ein int und d ein ist double , operator *(double,double) als besten Operator aus.Likewise, for the operation i * d, where i is an int and d is a double, overload resolution selects operator *(double,double) as the best operator.

Unäre numerische AktionenUnary numeric promotions

Unäre numerische herauf Stufung tritt für die Operanden der vordefinierten + - Operatoren, und auf ~ .Unary numeric promotion occurs for the operands of the predefined +, -, and ~ unary operators. Die Unäre numerische herauf Stufung besteht einfach aus der Umstellung von Operanden vom Typ sbyte , byte , short , ushort oder char in den-Typ int .Unary numeric promotion simply consists of converting operands of type sbyte, byte, short, ushort, or char to type int. Außerdem konvertiert die Unäre numerische herauf Stufung für den unären - Operator Operanden vom Typ uint in den Typ long .Additionally, for the unary - operator, unary numeric promotion converts operands of type uint to type long.

Binäre numerische AktionenBinary numeric promotions

Die binäre numerische herauf Stufung erfolgt bei den Operanden der vordefinierten + Operatoren,,,, - * / % , & , | , ^ ,,,,, == != > < >= und <= .Binary numeric promotion occurs for the operands of the predefined +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. Die binäre numerische herauf Stufung konvertiert beide Operanden implizit in einen gemeinsamen Typ, der bei nicht relationalen Operatoren auch zum Ergebnistyp des Vorgangs wird.Binary numeric promotion implicitly converts both operands to a common type which, in case of the non-relational operators, also becomes the result type of the operation. Die binäre numerische herauf Stufung besteht aus der Anwendung der folgenden Regeln in der Reihenfolge, in der Sie angezeigt werden:Binary numeric promotion consists of applying the following rules, in the order they appear here:

  • Wenn einer der beiden Operanden vom Typ ist decimal , wird der andere Operand in den Typ konvertiert decimal , oder es tritt ein Bindungs Zeitfehler auf, wenn der andere Operand vom Typ float oder ist double .If either operand is of type decimal, the other operand is converted to type decimal, or a binding-time error occurs if the other operand is of type float or double.
  • Wenn einer der beiden Operanden vom Typ ist double , wird der andere Operand in den Typ konvertiert double .Otherwise, if either operand is of type double, the other operand is converted to type double.
  • Wenn einer der beiden Operanden vom Typ ist float , wird der andere Operand in den Typ konvertiert float .Otherwise, if either operand is of type float, the other operand is converted to type float.
  • Andernfalls, wenn einer der beiden Operanden vom Typ ist ulong , wird der andere Operand in den Typ konvertiert ulong , oder es tritt ein Bindungs Zeitfehler auf, wenn der andere Operand vom Typ sbyte , short , int oder ist long .Otherwise, if either operand is of type ulong, the other operand is converted to type ulong, or a binding-time error occurs if the other operand is of type sbyte, short, int, or long.
  • Wenn einer der beiden Operanden vom Typ ist long , wird der andere Operand in den Typ konvertiert long .Otherwise, if either operand is of type long, the other operand is converted to type long.
  • Wenn einer der beiden uint Operanden vom Typ und der andere Operand vom Typ sbyte , oder ist short int , werden beide Operanden in den Typ konvertiert long .Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
  • Wenn einer der beiden Operanden vom Typ ist uint , wird der andere Operand in den Typ konvertiert uint .Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • Andernfalls werden beide Operanden in den Typ konvertiert int .Otherwise, both operands are converted to type int.

Beachten Sie, dass die erste Regel Vorgänge, die den decimal Typ mit den double Typen und mischen, nicht zulässt float .Note that the first rule disallows any operations that mix the decimal type with the double and float types. Die Regel folgt der Tatsache, dass keine impliziten Konvertierungen zwischen dem- decimal Typ und dem-Typ und dem-Typ vorhanden sind double float .The rule follows from the fact that there are no implicit conversions between the decimal type and the double and float types.

Beachten Sie außerdem, dass es nicht möglich ist, dass ein Operand vom Typ ulong ist, wenn der andere Operand einen ganzzahligen Typ mit Vorzeichen hat.Also note that it is not possible for an operand to be of type ulong when the other operand is of a signed integral type. Der Grund dafür ist, dass kein ganzzahliger Typ vorhanden ist, der den vollständigen Bereich von und die ganzzahligen Typen mit Vorzeichen darstellen kann ulong .The reason is that no integral type exists that can represent the full range of ulong as well as the signed integral types.

In beiden oben genannten Fällen kann ein Umwandlungs Ausdruck verwendet werden, um einen Operanden explizit in einen Typ zu konvertieren, der mit dem anderen Operanden kompatibel ist.In both of the above cases, a cast expression can be used to explicitly convert one operand to a type that is compatible with the other operand.

Im BeispielIn the example

decimal AddPercent(decimal x, double percent) {
    return x * (1.0 + percent / 100.0);
}

ein Fehler bei der Bindungs Zeit tritt auf, weil ein decimal nicht mit einem multipliziert werden kann double .a binding-time error occurs because a decimal cannot be multiplied by a double. Der Fehler wird behoben, indem der zweite Operand wie folgt explizit in umgerechnet wird decimal :The error is resolved by explicitly converting the second operand to decimal, as follows:

decimal AddPercent(decimal x, double percent) {
    return x * (decimal)(1.0 + percent / 100.0);
}

„Lifted“ OperatorenLifted operators

Mithilfe von aufzurufenden Operatoren können vordefinierte und benutzerdefinierte Operatoren, die nicht auf NULL festleg Bare Werttypen angewendet werden, auch mit null-fähigen Formularen dieser Typen verwendet werdenLifted operators permit predefined and user-defined operators that operate on non-nullable value types to also be used with nullable forms of those types. Gesteigerte Operatoren werden aus vordefinierten und benutzerdefinierten Operatoren erstellt, die bestimmte Anforderungen erfüllen, wie im folgenden beschrieben:Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:

  • Für die unären OperatorenFor the unary operators

    +  ++  -  --  !  ~
    

    eine angehobene Form eines Operators ist vorhanden, wenn der Operand und die Ergebnistypen beide Werttypen sind, die keine NULL-Werte zulassen.a lifted form of an operator exists if the operand and result types are both non-nullable value types. Das angefügte Formular wird erstellt, indem ein einzelner ? Modifizierer zu den Operanden-und Ergebnistypen hinzugefügt wird.The lifted form is constructed by adding a single ? modifier to the operand and result types. Der Operator "angehoben" erzeugt einen NULL-Wert, wenn der Operand NULL ist.The lifted operator produces a null value if the operand is null. Andernfalls entpackt der angehobene Operator den Operanden, wendet den zugrunde liegenden Operator an und umschließt das Ergebnis.Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.

  • Für die binären OperatorenFor the binary operators

    +  -  *  /  %  &  |  ^  <<  >>
    

    ein angezeigter Typ eines Operators ist vorhanden, wenn der Operand und die Ergebnistypen alle Werttypen darstellen, die keine NULL-Werte zulassen.a lifted form of an operator exists if the operand and result types are all non-nullable value types. Das angefügte Formular wird erstellt ? , indem jedem Operanden und Ergebnistyp ein einzelner Modifizierer hinzugefügt wird.The lifted form is constructed by adding a single ? modifier to each operand and result type. Der gesteigerte Operator erzeugt einen NULL-Wert, wenn ein oder beide Operanden NULL sind (eine Ausnahme ist der & -Operator und der-Operator | des- bool? Typs, wie in booleschen logischen Operatorenbeschrieben).The lifted operator produces a null value if one or both operands are null (an exception being the & and | operators of the bool? type, as described in Boolean logical operators). Andernfalls entpackt der angehobene Operator die Operanden, wendet den zugrunde liegenden Operator an und umschließt das Ergebnis.Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.

  • Für die Gleichheits OperatorenFor the equality operators

    ==  !=
    

    eine angehobene Form eines Operators ist vorhanden, wenn die Operanden Typen sowohl nicht auf NULL festleg Bare Werttypen als auch, wenn der Ergebnistyp ist bool .a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. Das angefügte Formular wird erstellt, indem einem ? Operanden ein einzelner Modifizierer hinzugefügt wird.The lifted form is constructed by adding a single ? modifier to each operand type. Der Operator "angehoben" berücksichtigt zwei NULL-Werte gleich, und ein NULL-Wert entspricht keinem Wert, der ungleich NULL ist.The lifted operator considers two null values equal, and a null value unequal to any non-null value. Wenn beide Operanden nicht NULL sind, entpackt der angehobene Operator die Operanden und wendet den zugrunde liegenden Operator an, um das Ergebnis zu erhalten bool .If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

  • Für die relationalen OperatorenFor the relational operators

    <  >  <=  >=
    

    eine angehobene Form eines Operators ist vorhanden, wenn die Operanden Typen sowohl nicht auf NULL festleg Bare Werttypen als auch, wenn der Ergebnistyp ist bool .a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. Das angefügte Formular wird erstellt, indem einem ? Operanden ein einzelner Modifizierer hinzugefügt wird.The lifted form is constructed by adding a single ? modifier to each operand type. Der Operator "angehoben" erzeugt den Wert, false Wenn ein oder beide Operanden NULL sind.The lifted operator produces the value false if one or both operands are null. Andernfalls entpackt der angehobene Operator die Operanden und wendet den zugrunde liegenden Operator an, um das Ergebnis zu erhalten bool .Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

Member lookup (Membersuche)Member lookup

Bei der Suche nach Membern handelt es sich um den Prozess, bei dem die Bedeutung eines Namens im Kontext eines Typs bestimmt wird.A member lookup is the process whereby the meaning of a name in the context of a type is determined. Eine Element Suche kann als Teil der Auswertung eines Simple_name (einfache Namen) oder eines member_access (Member Access) in einem Ausdruck auftreten.A member lookup can occur as part of evaluating a simple_name (Simple names) or a member_access (Member access) in an expression. Wenn die Simple_name oder member_access als primary_expression einer invocation_expression (Methodenaufrufe) auftritt, wird der Member als aufgerufen bezeichnet.If the simple_name or member_access occurs as the primary_expression of an invocation_expression (Method invocations), the member is said to be invoked.

Wenn ein Member eine Methode oder ein Ereignis ist, oder wenn es sich um eine Konstante, ein Feld oder eine Eigenschaft eines Delegattyps (Delegaten ) oderdes Typs dynamic (des dynamischen Typs) handelt, wird der Member als Aufruf barer Ausdruck bezeichnet.If a member is a method or event, or if it is a constant, field or property of either a delegate type (Delegates) or the type dynamic (The dynamic type), then the member is said to be invocable.

Die Element Suche berücksichtigt nicht nur den Namen eines Members, sondern auch die Anzahl der Typparameter, die der Member hat und ob auf den Member zugegriffen werden kann.Member lookup considers not only the name of a member but also the number of type parameters the member has and whether the member is accessible. Für die Suche nach Membern verfügen generische Methoden und generische generische Typen über die Anzahl der Typparameter, die in den jeweiligen Deklarationen angegeben sind, und alle anderen Member haben keine Typparameter.For the purposes of member lookup, generic methods and nested generic types have the number of type parameters indicated in their respective declarations and all other members have zero type parameters.

Eine Member-Suche mit einem Namen  N mit K   Typparametern in einem Typ  T wird wie folgt verarbeitet:A member lookup of a name N with K type parameters in a type T is processed as follows:

  • Zuerst wird ein Satz barrierefreier Member mit dem Namen  N bestimmt:First, a set of accessible members named N is determined:
    • Wenn T ein Typparameter ist, dann entspricht der Satz der Menge der zugreif baren Member, die  N in jedem der Typen benannt sind, die als primäre Einschränkung oder sekundäre Einschränkung (Typparameter Einschränkungen) für angegeben  T sind, sowie der Menge der zugänglichen Member, die in benannt sind  N object .If T is a type parameter, then the set is the union of the sets of accessible members named N in each of the types specified as a primary constraint or secondary constraint (Type parameter constraints) for T, along with the set of accessible members named N in object.
    • Andernfalls besteht der Satz aus allen zugänglichen (Member Access) Membern  N , die in benannt  T sind, einschließlich der geerbten Member und der zugänglichen Member  N in object .Otherwise, the set consists of all accessible (Member access) members named N in T, including inherited members and the accessible members named N in object. Wenn T ein konstruierter Typ ist, wird der Satz von Membern durch Ersetzen von Typargumenten abgerufen, wie in Members von konstruierten Typenbeschrieben.If T is a constructed type, the set of members is obtained by substituting type arguments as described in Members of constructed types. Member, die einen- override Modifizierer einschließen, werden aus dem Satz ausgeschlossen.Members that include an override modifier are excluded from the set.
  • Wenn dann auf K 0 (null) gesetzt ist, werden alle nsted-Typen, deren Deklarationen Typparameter enthalten, entferntNext, if K is zero, all nested types whose declarations include type parameters are removed. Wenn K nicht 0 (null) ist, werden alle Elemente mit einer anderen Anzahl von Typparametern entfernt.If K is not zero, all members with a different number of type parameters are removed. Beachten Sie, dass K , wenn 0 (null) ist, keine Methoden mit Typparametern entfernt werden, da der Typrückschluss-Prozess (Typrückschluss) möglicherweise die Typargumente ableiten kann.Note that when K is zero, methods having type parameters are not removed, since the type inference process (Type inference) might be able to infer the type arguments.
  • Wenn der Member aufgerufen wird, werden alle nicht Aufruf baren Member aus dem Satz entfernt.Next, if the member is invoked, all non-invocable members are removed from the set.
  • Als nächstes werden Elemente, die von anderen Membern ausgeblendet werden, aus dem Satz entfernt.Next, members that are hidden by other members are removed from the set. Für jedes Element S.M im Satz, wobei S der Typ ist, in dem der Member  M deklariert wird, werden die folgenden Regeln angewendet:For every member S.M in the set, where S is the type in which the member M is declared, the following rules are applied:
    • Wenn M eine Konstante, ein Feld, eine Eigenschaft, ein Ereignis oder ein Enumerationsmember ist, werden alle in einem Basistyp von deklarierten Member S aus dem Satz entfernt.If M is a constant, field, property, event, or enumeration member, then all members declared in a base type of S are removed from the set.
    • Wenn M eine Typdeklaration ist, werden alle nicht-Typen, die in einem Basistyp von deklariert S sind, aus dem Satz entfernt, und alle Typdeklarationen mit der gleichen Anzahl von Typparametern, die M in einem Basistyp von deklariert S werden, werden aus dem Satz entfernt.If M is a type declaration, then all non-types declared in a base type of S are removed from the set, and all type declarations with the same number of type parameters as M declared in a base type of S are removed from the set.
    • Wenn M eine Methode ist, werden alle nicht-Methoden Elemente, die in einem Basistyp von deklariert S sind, aus dem Satz entfernt.If M is a method, then all non-method members declared in a base type of S are removed from the set.
  • Als nächstes werden Schnittstellenmember, die von Klassenmembern ausgeblendet werden, aus dem Satz entfernt.Next, interface members that are hidden by class members are removed from the set. Dieser Schritt wirkt sich nur dann aus, wenn T ein Typparameter ist und T sowohl eine effektive Basisklasse als als object auch eine nicht leere effektive Schnittstellen Menge aufweist (Typparameter Einschränkungen).This step only has an effect if T is a type parameter and T has both an effective base class other than object and a non-empty effective interface set (Type parameter constraints). Für jeden Member S.M in der Menge, wobei S der Typ ist, in dem der Member M deklariert wird, werden die folgenden Regeln angewendet, wenn S eine andere Klassen Deklaration als ist object :For every member S.M in the set, where S is the type in which the member M is declared, the following rules are applied if S is a class declaration other than object:
    • Wenn M eine Konstante, ein Feld, eine Eigenschaft, ein Ereignis, ein Enumerationsmember oder eine Typdeklaration ist, werden alle in einer Schnittstellen Deklaration deklarierten Member aus dem Satz entfernt.If M is a constant, field, property, event, enumeration member, or type declaration, then all members declared in an interface declaration are removed from the set.
    • Wenn M eine Methode ist, werden alle nicht-Methoden Member, die in einer Schnittstellen Deklaration deklariert sind, aus dem Satz entfernt, und alle Methoden mit derselben Signatur, wie Sie M in einer Schnittstellen Deklaration deklariert sind, werden aus dem Satz entfernt.If M is a method, then all non-method members declared in an interface declaration are removed from the set, and all methods with the same signature as M declared in an interface declaration are removed from the set.
  • Schließlich wird das Ergebnis der Suche bestimmt, wenn verborgene Member entfernt wurden:Finally, having removed hidden members, the result of the lookup is determined:
    • Wenn der Satz aus einem einzelnen Member besteht, der keine Methode ist, dann ist dieser Member das Ergebnis der Suche.If the set consists of a single member that is not a method, then this member is the result of the lookup.
    • Andernfalls ist diese Gruppe von Methoden das Ergebnis der Suche, wenn der Satz nur Methoden enthält.Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
    • Andernfalls ist die Suche mehrdeutig, und es tritt ein Bindungs Zeitfehler auf.Otherwise, the lookup is ambiguous, and a binding-time error occurs.

Für Member-suchen in anderen Typen als Typparameter und Schnittstellen und für Member-suchen in Schnittstellen, die nur eine einzelne Vererbung haben (jede Schnittstelle in der Vererbungs Kette weist genau null oder eine direkte Basisschnittstelle auf), besteht die Auswirkung der Such Regeln lediglich darin, dass abgeleitete Member Basiselemente mit dem gleichen Namen oder der gleichen Signatur ausblenden.For member lookups in types other than type parameters and interfaces, and member lookups in interfaces that are strictly single-inheritance (each interface in the inheritance chain has exactly zero or one direct base interface), the effect of the lookup rules is simply that derived members hide base members with the same name or signature. Solche Suchvorgänge mit einer einzelnen Vererbung sind nie mehrdeutig.Such single-inheritance lookups are never ambiguous. Die Mehrdeutigkeiten, die möglicherweise von Member-suchen in Schnittstellen mit mehreren Vererbungen auftreten können, werden unter Zugreifen auf die Benutzeroberflächebeschrieben.The ambiguities that can possibly arise from member lookups in multiple-inheritance interfaces are described in Interface member access.

Basis TypenBase types

Für Zwecke der Element Suche wird ein Typ T als die folgenden Basis Typen betrachtet:For purposes of member lookup, a type T is considered to have the following base types:

  • Wenn T ist object , dann T hat keinen Basistyp.If T is object, then T has no base type.
  • Wenn T ein enum_type ist, sind die Basis Typen von T die Klassentypen System.Enum , System.ValueType und object .If T is an enum_type, the base types of T are the class types System.Enum, System.ValueType, and object.
  • Wenn T ein struct_type ist, sind die Basis Typen von T die Klassentypen System.ValueType und object .If T is a struct_type, the base types of T are the class types System.ValueType and object.
  • Wenn T ein class_type ist, sind die Basis Typen von die T Basisklassen von T , einschließlich des Klassen Typs object .If T is a class_type, the base types of T are the base classes of T, including the class type object.
  • Wenn T ein INTERFACE_TYPE ist, sind die Basis Typen von T die Basis Schnittstellen von T und der-Klassentyp object .If T is an interface_type, the base types of T are the base interfaces of T and the class type object.
  • Wenn T ein array_type ist, sind die Basis Typen von T die Klassentypen System.Array und object .If T is an array_type, the base types of T are the class types System.Array and object.
  • Wenn T ein delegate_type ist, sind die Basis Typen von T die Klassentypen System.Delegate und object .If T is a delegate_type, the base types of T are the class types System.Delegate and object.

Function members (Funktionselemente)Function members

Funktionsmember sind Elemente, die ausführbare Anweisungen enthalten.Function members are members that contain executable statements. Funktionsmember sind immer Member von Typen und können keine Member von Namespaces sein.Function members are always members of types and cannot be members of namespaces. C# definiert die folgenden Kategorien von Funktionsmembern:C# defines the following categories of function members:

  • MethodenMethods
  • EigenschaftenProperties
  • EreignisseEvents
  • IndexerIndexers
  • Benutzerdefinierte OperatorenUser-defined operators
  • InstanzkonstruktorenInstance constructors
  • Statische KonstruktorenStatic constructors
  • DestruktorenDestructors

Mit Ausnahme der destrukturtoren und statischer Konstruktoren (die nicht explizit aufgerufen werden können) werden die in Funktionsmembern enthaltenen Anweisungen durch Funktionselement Aufrufe ausgeführt.Except for destructors and static constructors (which cannot be invoked explicitly), the statements contained in function members are executed through function member invocations. Die tatsächliche Syntax zum Schreiben eines Funktionsmember-aufzurufenden ist von der jeweiligen Funktionsmember-Kategorie abhängig.The actual syntax for writing a function member invocation depends on the particular function member category.

Die Argumentliste (Argumentlisten) eines Funktionsmember-aufzurufenden enthält tatsächliche Werte oder Variablen Verweise für die Parameter des Funktionsmembers.The argument list (Argument lists) of a function member invocation provides actual values or variable references for the parameters of the function member.

Aufrufe generischer Methoden können den Typrückschluss verwenden, um den Satz von Typargumenten zu ermitteln, die an die Methode übergeben werden sollen.Invocations of generic methods may employ type inference to determine the set of type arguments to pass to the method. Dieser Prozess wird unter Typrückschlussbeschrieben.This process is described in Type inference.

Aufrufe von Methoden, Indexern, Operatoren und Instanzkonstruktoren verwenden die Überladungs Auflösung, um zu bestimmen, welcher Satz von Funktions Membern aufgerufen werden soll.Invocations of methods, indexers, operators and instance constructors employ overload resolution to determine which of a candidate set of function members to invoke. Dieser Prozess wird in der Überladungs Auflösungbeschrieben.This process is described in Overload resolution.

Sobald ein bestimmter Funktionsmember zur Bindungs Zeit (möglicherweise durch Überladungs Auflösung) identifiziert wurde, wird der tatsächliche Lauf Zeit Prozess des Aufrufs des Funktionsmembers in der Kompilierzeit Überprüfung der dynamischen Überladungs Auflösungbeschrieben.Once a particular function member has been identified at binding-time, possibly through overload resolution, the actual run-time process of invoking the function member is described in Compile-time checking of dynamic overload resolution.

In der folgenden Tabelle wird die Verarbeitung zusammengefasst, die in-Konstrukten mit den sechs Kategorien von Funktionsmembern stattfindet, die explizit aufgerufen werden können.The following table summarizes the processing that takes place in constructs involving the six categories of function members that can be explicitly invoked. In der-Tabelle e geben,, x y und value Ausdrücke an, die als Variablen oder Werte klassifiziert sind, T einen Ausdruck, der als Typ klassifiziert ist, F den einfachen Namen einer Methode und P den einfachen Namen einer Eigenschaft angibt.In the table, e, x, y, and value indicate expressions classified as variables or values, T indicates an expression classified as a type, F is the simple name of a method, and P is the simple name of a property.

ErstellenConstruct BeispielExample BeschreibungDescription
MethodenaufrufMethod invocation F(x,y) Die Überladungs Auflösung wird angewendet, um die beste Methode F in der enthaltenden Klasse oder Struktur auszuwählen.Overload resolution is applied to select the best method F in the containing class or struct. Die-Methode wird mit der Argumentliste aufgerufen (x,y) .The method is invoked with the argument list (x,y). Wenn die-Methode nicht ist static , ist der Instanzausdruck this .If the method is not static, the instance expression is this.
T.F(x,y) Die Überladungs Auflösung wird angewendet, um die beste Methode F in der Klasse oder Struktur auszuwählen T .Overload resolution is applied to select the best method F in the class or struct T. Ein Bindungs Zeit Fehler tritt auf, wenn die Methode nicht ist static .A binding-time error occurs if the method is not static. Die-Methode wird mit der Argumentliste aufgerufen (x,y) .The method is invoked with the argument list (x,y).
e.F(x,y) Die Überladungs Auflösung wird angewendet, um die beste Methode F in der Klasse, Struktur oder Schnittstelle auszuwählen, die durch den Typ von angegeben wird e .Overload resolution is applied to select the best method F in the class, struct, or interface given by the type of e. Ein Bindungs Zeit Fehler tritt auf, wenn die-Methode ist static .A binding-time error occurs if the method is static. Die-Methode wird mit dem Instanzausdruck e und der Argumentliste aufgerufen (x,y) .The method is invoked with the instance expression e and the argument list (x,y).
EigenschaftenzugriffProperty access P Der- get Accessor der Eigenschaft P in der enthaltenden Klasse oder Struktur wird aufgerufen.The get accessor of the property P in the containing class or struct is invoked. Ein Kompilierzeitfehler tritt auf, wenn P schreibgeschützt ist.A compile-time error occurs if P is write-only. Wenn P nicht ist static , ist der Instanzausdruck this .If P is not static, the instance expression is this.
P = value Der- set Accessor der Eigenschaft P in der enthaltenden Klasse oder Struktur wird mit der Argumentliste (value) aufgerufen.The set accessor of the property P in the containing class or struct is invoked with the argument list (value). Ein Kompilierzeitfehler tritt auf, wenn schreibgeschützt P ist.A compile-time error occurs if P is read-only. Wenn P nicht ist static , ist der Instanzausdruck this .If P is not static, the instance expression is this.
T.P Der- get Accessor der Eigenschaft P in der Klasse oder Struktur T wird aufgerufen.The get accessor of the property P in the class or struct T is invoked. Ein Kompilierzeitfehler tritt auf, wenn P nicht ist static oder wenn P schreibgeschützt ist.A compile-time error occurs if P is not static or if P is write-only.
T.P = value Der- set Accessor der Eigenschaft P in der Klasse oder Struktur T wird mit der Argumentliste aufgerufen (value) .The set accessor of the property P in the class or struct T is invoked with the argument list (value). Ein Kompilierzeitfehler tritt auf, wenn P nicht ist static oder wenn schreibgeschützt P ist.A compile-time error occurs if P is not static or if P is read-only.
e.P Der- get Accessor der Eigenschaft P in der Klasse, Struktur oder Schnittstelle, die durch den-Typ angegeben e wird, wird mit dem Instanzausdruck aufgerufen e .The get accessor of the property P in the class, struct, or interface given by the type of e is invoked with the instance expression e. Ein Fehler bei der Bindungs Zeit tritt auf, wenn P ist static oder wenn P schreibgeschützt ist.A binding-time error occurs if P is static or if P is write-only.
e.P = value Der set -Accessor der Eigenschaft P in der Klasse, Struktur oder Schnittstelle, die durch den Typ von angegeben e wird, wird mit dem Instanzausdruck e und der Argumentliste aufgerufen (value) .The set accessor of the property P in the class, struct, or interface given by the type of e is invoked with the instance expression e and the argument list (value). Ein Fehler bei der Bindungs Zeit tritt auf, wenn P ist static oder wenn schreibgeschützt P ist.A binding-time error occurs if P is static or if P is read-only.
Ereignis ZugriffEvent access E += value Der- add Accessor des Ereignisses E in der enthaltenden Klasse oder Struktur wird aufgerufen.The add accessor of the event E in the containing class or struct is invoked. Wenn E nicht statisch ist, ist der Instanzausdruck this .If E is not static, the instance expression is this.
E -= value Der- remove Accessor des Ereignisses E in der enthaltenden Klasse oder Struktur wird aufgerufen.The remove accessor of the event E in the containing class or struct is invoked. Wenn E nicht statisch ist, ist der Instanzausdruck this .If E is not static, the instance expression is this.
T.E += value Der- add Accessor des Ereignisses E in der Klasse oder Struktur T wird aufgerufen.The add accessor of the event E in the class or struct T is invoked. Ein Fehler bei der Bindungs Zeit tritt auf, wenn E nicht statisch ist.A binding-time error occurs if E is not static.
T.E -= value Der- remove Accessor des Ereignisses E in der Klasse oder Struktur T wird aufgerufen.The remove accessor of the event E in the class or struct T is invoked. Ein Fehler bei der Bindungs Zeit tritt auf, wenn E nicht statisch ist.A binding-time error occurs if E is not static.
e.E += value Der- add Accessor des Ereignisses E in der Klasse, Struktur oder Schnittstelle, die durch den-Typ angegeben e wird, wird mit dem Instanzausdruck aufgerufen e .The add accessor of the event E in the class, struct, or interface given by the type of e is invoked with the instance expression e. Ein Fehler bei der Bindungs Zeit tritt auf, wenn E statisch ist.A binding-time error occurs if E is static.
e.E -= value Der- remove Accessor des Ereignisses E in der Klasse, Struktur oder Schnittstelle, die durch den-Typ angegeben e wird, wird mit dem Instanzausdruck aufgerufen e .The remove accessor of the event E in the class, struct, or interface given by the type of e is invoked with the instance expression e. Ein Fehler bei der Bindungs Zeit tritt auf, wenn E statisch ist.A binding-time error occurs if E is static.
IndexerzugriffIndexer access e[x,y] Die Überladungs Auflösung wird angewendet, um den besten Indexer in der Klasse, Struktur oder Schnittstelle auszuwählen, die durch den Typ von e angegeben wird.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. Der get -Accessor des Indexers wird mit dem Instanzausdruck e und der Argumentliste aufgerufen (x,y) .The get accessor of the indexer is invoked with the instance expression e and the argument list (x,y). Ein Bindungs Zeit Fehler tritt auf, wenn der Indexer schreibgeschützt ist.A binding-time error occurs if the indexer is write-only.
e[x,y] = value Die Überladungs Auflösung wird angewendet, um den besten Indexer in der Klasse, Struktur oder Schnittstelle auszuwählen, die durch den Typ von angegeben wird e .Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. Der set -Accessor des Indexers wird mit dem Instanzausdruck e und der Argumentliste aufgerufen (x,y,value) .The set accessor of the indexer is invoked with the instance expression e and the argument list (x,y,value). Ein Bindungs Zeit Fehler tritt auf, wenn der Indexer schreibgeschützt ist.A binding-time error occurs if the indexer is read-only.
Operator AufrufOperator invocation -x Die Überladungs Auflösung wird angewendet, um den besten unären Operator in der Klasse oder Struktur auszuwählen, die durch den Typ von angegeben wird x .Overload resolution is applied to select the best unary operator in the class or struct given by the type of x. Der ausgewählte Operator wird mit der Argumentliste aufgerufen (x) .The selected operator is invoked with the argument list (x).
x + y Die Überladungs Auflösung wird angewendet, um den besten binären Operator in den Klassen oder Strukturen auszuwählen, die von den Typen von und angegeben werden x y .Overload resolution is applied to select the best binary operator in the classes or structs given by the types of x and y. Der ausgewählte Operator wird mit der Argumentliste aufgerufen (x,y) .The selected operator is invoked with the argument list (x,y).
InstanzkonstruktoraufrufInstance constructor invocation new T(x,y) Die Überladungs Auflösung wird angewendet, um den besten Instanzkonstruktor in der Klasse oder Struktur auszuwählen T .Overload resolution is applied to select the best instance constructor in the class or struct T. Der Instanzkonstruktor wird mit der Argumentliste aufgerufen (x,y) .The instance constructor is invoked with the argument list (x,y).

Argument ListenArgument lists

Jeder Funktionsmember und Delegataufruf enthält eine Argumentliste, die tatsächliche Werte oder Variablen Verweise für die Parameter des Funktionsmembers bereitstellt.Every function member and delegate invocation includes an argument list which provides actual values or variable references for the parameters of the function member. Die Syntax zum Angeben der Argumentliste eines Funktionsmember-aufzurufenden ist von der Funktionsmember-Kategorie abhängig:The syntax for specifying the argument list of a function member invocation depends on the function member category:

  • Bei Instanzkonstruktoren, Methoden, Indexern und Delegaten werden die Argumente als argument_list angegeben, wie unten beschrieben.For instance constructors, methods, indexers and delegates, the arguments are specified as an argument_list, as described below. Bei Indexers schließt beim Aufrufen der-Zugriffsmethode die set Argumentliste zusätzlich den Ausdruck ein, der als rechter Operand des Zuweisungs Operators angegeben ist.For indexers, when invoking the set accessor, the argument list additionally includes the expression specified as the right operand of the assignment operator.
  • Bei-Eigenschaften ist die Argumentliste leer, wenn der- get Accessor aufgerufen wird, und besteht aus dem Ausdruck, der beim Aufrufen der Zugriffsmethode als rechter Operand des Zuweisungs Operators angegeben wurde set .For properties, the argument list is empty when invoking the get accessor, and consists of the expression specified as the right operand of the assignment operator when invoking the set accessor.
  • Bei Ereignissen besteht die Argumentliste aus dem Ausdruck, der als rechter Operand des or- += Operators angegeben ist -= .For events, the argument list consists of the expression specified as the right operand of the += or -= operator.
  • Bei benutzerdefinierten Operatoren besteht die Argumentliste aus dem einzelnen Operanden des unären Operators oder den beiden Operanden des binären Operators.For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator.

Die Argumente von Eigenschaften (Eigenschaften), Ereignissen (Ereignissen) und benutzerdefinierten Operatoren (Operatoren) werden immer als Wert Parameter (value-Parameter) übermittelt.The arguments of properties (Properties), events (Events), and user-defined operators (Operators) are always passed as value parameters (Value parameters). Die Argumente von Indexer (Indexer) werden immer als Wert Parameter (Wert Parameter) oder Parameter Arrays (Parameter Arrays) übergeben.The arguments of indexers (Indexers) are always passed as value parameters (Value parameters) or parameter arrays (Parameter arrays). Verweis-und Ausgabeparameter werden für diese Kategorien von Funktionsmembern nicht unterstützt.Reference and output parameters are not supported for these categories of function members.

Die Argumente eines Instanzkonstruktors, einer Methode, eines Indexers oder eines delegataufrufers werden als argument_list angegeben:The arguments of an instance constructor, method, indexer or delegate invocation are specified as an argument_list:

argument_list
    : argument (',' argument)*
    ;

argument
    : argument_name? argument_value
    ;

argument_name
    : identifier ':'
    ;

argument_value
    : expression
    | 'ref' variable_reference
    | 'out' variable_reference
    ;

Ein argument_list besteht aus einem oder mehreren Argumenten, getrennt durch Kommas.An argument_list consists of one or more argument s, separated by commas. Jedes Argument besteht aus einem optionalen argument_name gefolgt von einem argument_value.Each argument consists of an optional argument_name followed by an argument_value. Ein Argument mit einem argument_name wird als *benanntes Argument _ bezeichnet, wohingegen ein Argument * ohne argument_name ein *Positions Argument ist.An argument with an argument_name is referred to as a named argument _, whereas an _argument without an argument_name is a *positional argument_. Es ist ein Fehler für ein Positions Argument, das nach einem benannten Argument in einem _argument_list * angezeigt wird.It is an error for a positional argument to appear after a named argument in an _argument_list*.

Der argument_value kann eine der folgenden Formen annehmen:The argument_value can take one of the following forms:

  • Ein Ausdruck, der angibt, dass das Argument als Wert Parameter (Wert Parameter) übergeben wird.An expression, indicating that the argument is passed as a value parameter (Value parameters).
  • Das Schlüsselwort ref , gefolgt von einem variable_reference (Variablen Verweise), das angibt, dass das Argument als Verweis Parameter (Verweis Parameter) übergeben wird.The keyword ref followed by a variable_reference (Variable references), indicating that the argument is passed as a reference parameter (Reference parameters). Eine Variable muss definitiv zugewiesen werden (definitive Zuweisung), bevor Sie als Verweis Parameter übergeben werden kann.A variable must be definitely assigned (Definite assignment) before it can be passed as a reference parameter. Das Schlüsselwort out , gefolgt von einem variable_reference (Variablen Verweise), das angibt, dass das Argument als Ausgabeparameter (Ausgabeparameter) übergeben wird.The keyword out followed by a variable_reference (Variable references), indicating that the argument is passed as an output parameter (Output parameters). Eine Variable wird als definitiv zugewiesen (definitive Zuweisung) nach einem Funktionselement Aufruf, bei dem die Variable als Output-Parameter übergeben wird.A variable is considered definitely assigned (Definite assignment) following a function member invocation in which the variable is passed as an output parameter.

Entsprechende ParameterCorresponding parameters

Für jedes Argument in einer Argumentliste muss ein entsprechender Parameter im Funktions Member oder Delegaten vorhanden sein, der aufgerufen wird.For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.

Die im folgenden verwendete Parameterliste wird wie folgt bestimmt:The parameter list used in the following is determined as follows:

  • Bei virtuellen Methoden und indexatoren, die in Klassen definiert sind, wird die Parameterliste aus der spezifischsten Deklaration oder Überschreibung des Funktionsmembers ausgewählt, beginnend mit dem statischen Typ des Empfängers und Durchsuchen der zugehörigen Basisklassen.For virtual methods and indexers defined in classes, the parameter list is picked from the most specific declaration or override of the function member, starting with the static type of the receiver, and searching through its base classes.
  • Für Schnittstellen Methoden und Indexer wird die Parameterliste aus der spezifischsten Definition des Members ausgewählt, beginnend mit dem Schnittstellentyp und Durchsuchen der Basis Schnittstellen.For interface methods and indexers, the parameter list is picked form the most specific definition of the member, starting with the interface type and searching through the base interfaces. Wenn keine eindeutige Parameterliste gefunden wird, wird eine Parameterliste mit nicht zugänglichen Namen und optionalen Parametern erstellt, sodass Aufrufe keine benannten Parameter verwenden können oder keine optionalen Argumente weglassen.If no unique parameter list is found, a parameter list with inaccessible names and no optional parameters is constructed, so that invocations cannot use named parameters or omit optional arguments.
  • Bei partiellen Methoden wird die Parameterliste der definierenden partiellen Methoden Deklaration verwendet.For partial methods, the parameter list of the defining partial method declaration is used.
  • Für alle anderen Funktionsmember und Delegaten gibt es nur eine einzige Parameterliste, die verwendet wird.For all other function members and delegates there is only a single parameter list, which is the one used.

Die Position eines Arguments oder Parameters wird als die Anzahl der Argumente oder Parameter definiert, die in der Argumentliste oder Parameterliste vorangestellt sind.The position of an argument or parameter is defined as the number of arguments or parameters preceding it in the argument list or parameter list.

Die entsprechenden Parameter für Funktionsmember-Argumente werden wie folgt festgelegt:The corresponding parameters for function member arguments are established as follows:

  • Argumente im argument_list von Instanzkonstruktoren, Methoden, Indexern und Delegaten:Arguments in the argument_list of instance constructors, methods, indexers and delegates:
    • Ein Positions Argument, bei dem ein fester Parameter an derselben Position in der Parameterliste auftritt, entspricht diesem Parameter.A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter.
    • Ein Positions Argument eines Funktionsmembers mit einem Parameter Array, das in der normalen Form aufgerufen wird, entspricht dem Parameter Array, das an derselben Position in der Parameterliste vorkommen muss.A positional argument of a function member with a parameter array invoked in its normal form corresponds to the parameter array, which must occur at the same position in the parameter list.
    • Ein Positions Argument eines Funktionsmembers mit einem Parameter Array, das in der erweiterten Form aufgerufen wird, wobei kein fester Parameter an derselben Position in der Parameterliste auftritt, entspricht einem Element im Parameter Array.A positional argument of a function member with a parameter array invoked in its expanded form, where no fixed parameter occurs at the same position in the parameter list, corresponds to an element in the parameter array.
    • Ein benanntes Argument entspricht dem-Parameter mit dem gleichen Namen in der Parameterliste.A named argument corresponds to the parameter of the same name in the parameter list.
    • Bei Indexers set entspricht der als rechter Operand des Zuweisungs Operators angegebene Ausdruck dem impliziten value Parameter der Accessor-Deklaration, wenn der Accessor aufgerufen wird set .For indexers, when invoking the set accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit value parameter of the set accessor declaration.
  • Bei-Eigenschaften get gibt es keine Argumente, wenn der-Accessor aufgerufen wird.For properties, when invoking the get accessor there are no arguments. Wenn der- set Accessor aufgerufen wird, entspricht der als rechter Operand des Zuweisungs Operators angegebene Ausdruck dem impliziten value Parameter der set Accessordeklaration.When invoking the set accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit value parameter of the set accessor declaration.
  • Bei benutzerdefinierten unären Operatoren (einschließlich Konvertierungen) entspricht der einzelne Operand dem einzelnen Parameter der Operator Deklaration.For user-defined unary operators (including conversions), the single operand corresponds to the single parameter of the operator declaration.
  • Für benutzerdefinierte binäre Operatoren entspricht der linke Operand dem ersten Parameter, und der rechte Operand entspricht dem zweiten Parameter der Operator Deklaration.For user-defined binary operators, the left operand corresponds to the first parameter, and the right operand corresponds to the second parameter of the operator declaration.

Lauf Zeit Auswertung von ArgumentlistenRun-time evaluation of argument lists

Während der Lauf Zeit Verarbeitung eines Funktionsmember-aufzurufenden (Kompilierzeit Überprüfung der dynamischen Überladungs Auflösung) werden die Ausdrücke oder Variablen Verweise einer Argumentliste in der Reihenfolge von links nach rechts ausgewertet, wie folgt:During the run-time processing of a function member invocation (Compile-time checking of dynamic overload resolution), the expressions or variable references of an argument list are evaluated in order, from left to right, as follows:

  • Bei einem value-Parameter wird der Argument Ausdruck ausgewertet und eine implizite Konvertierung (implizite Konvertierungen) in den entsprechenden Parametertyp durchgeführt.For a value parameter, the argument expression is evaluated and an implicit conversion (Implicit conversions) to the corresponding parameter type is performed. Der resultierende Wert wird zum Anfangswert des value-Parameters im Funktionselement Aufruf.The resulting value becomes the initial value of the value parameter in the function member invocation.
  • Bei einem Verweis-oder Ausgabeparameter wird der Variablen Verweis ausgewertet, und der resultierende Speicherort wird zu dem Speicherort, der durch den-Parameter im Aufruf der Funktionselemente dargestellt wird.For a reference or output parameter, the variable reference is evaluated and the resulting storage location becomes the storage location represented by the parameter in the function member invocation. Wenn der als Verweis oder Ausgabeparameter angegebene Variablen Verweis ein Array Element einer reference_type ist, wird eine Lauf Zeit Überprüfung durchgeführt, um sicherzustellen, dass der Elementtyp des Arrays mit dem Parametertyp identisch ist.If the variable reference given as a reference or output parameter is an array element of a reference_type, a run-time check is performed to ensure that the element type of the array is identical to the type of the parameter. Wenn bei dieser Überprüfung ein Fehler auftritt, wird eine ausgelöst System.ArrayTypeMismatchException .If this check fails, a System.ArrayTypeMismatchException is thrown.

Methoden, Indexer und Instanzkonstruktoren können Ihren äußersten ganz rechts Parameter als Parameter Array deklarieren (Parameter Arrays).Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array (Parameter arrays). Solche Funktionsmember werden entweder in ihrer normalen Form oder in der erweiterten Form aufgerufen, je nachdem, welche anwendbar ist (anwendbares Funktionsmember):Such function members are invoked either in their normal form or in their expanded form depending on which is applicable (Applicable function member):

  • Wenn ein Funktionsmember mit einem Parameter Array in der normalen Form aufgerufen wird, muss das für das Parameter Array angegebene Argument ein einzelner Ausdruck sein, der implizit konvertierbar (implizite Konvertierungen) in den Typ des Parameter Arrays ist.When a function member with a parameter array is invoked in its normal form, the argument given for the parameter array must be a single expression that is implicitly convertible (Implicit conversions) to the parameter array type. In diesem Fall verhält sich das Parameter Array genau wie ein value-Parameter.In this case, the parameter array acts precisely like a value parameter.
  • Wenn ein Funktionsmember mit einem Parameter Array in der erweiterten Form aufgerufen wird, muss der Aufruf NULL oder mehr Positions Argumente für das Parameter Array angeben, wobei jedes Argument ein Ausdruck ist, der implizit konvertierbar (implizite Konvertierungen) in den Elementtyp des Parameter Arrays ist.When a function member with a parameter array is invoked in its expanded form, the invocation must specify zero or more positional 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 erstellt der Aufruf eine Instanz des Parameter Array Typs mit einer Länge, die der Anzahl der Argumente entspricht, initialisiert die Elemente der Array Instanz mit den angegebenen Argument Werten und verwendet die neu erstellte Array Instanz als tatsächliches 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.

Die Ausdrücke einer Argumentliste werden immer in der Reihenfolge ausgewertet, in der Sie geschrieben werden.The expressions of an argument list are always evaluated in the order they are written. Das BeispielThus, the example

class Test
{
    static void F(int x, int y = -1, int z = -2) {
        System.Console.WriteLine("x = {0}, y = {1}, z = {2}", x, y, z);
    }

    static void Main() {
        int i = 0;
        F(i++, i++, i++);
        F(z: i++, x: i++);
    }
}

erzeugt die Ausgabeproduces the output

x = 0, y = 1, z = 2
x = 4, y = -1, z = 3

Die Array-Co-Varianz Regeln (Array-Kovarianz) erlauben, dass ein Wert eines Arraytyps A[] ein Verweis auf eine Instanz eines Arraytyps B[] ist, vorausgesetzt, dass eine implizite Verweis Konvertierung von in vorhanden ist B A .The array co-variance rules (Array covariance) permit a value of an array type A[] to be a reference to an instance of an array type B[], provided an implicit reference conversion exists from B to A. Aufgrund dieser Regeln ist eine Lauf Zeit Überprüfung erforderlich, wenn ein Array Element einer reference_type als Verweis-oder Ausgabeparameter übergeben wird, um sicherzustellen, dass der tatsächliche Elementtyp des Arrays mit dem des Parameters identisch ist.Because of these rules, when an array element of a reference_type is passed as a reference or output parameter, a run-time check is required to ensure that the actual element type of the array is identical to that of the parameter. Im BeispielIn the example

class Test
{
    static void F(ref object x) {...}

    static void Main() {
        object[] a = new object[10];
        object[] b = new string[10];
        F(ref a[0]);        // Ok
        F(ref b[1]);        // ArrayTypeMismatchException
    }
}

der zweite Aufruf von F bewirkt System.ArrayTypeMismatchException , dass eine ausgelöst wird, da der tatsächliche Elementtyp von b ist string und nicht object .the second invocation of F causes a System.ArrayTypeMismatchException to be thrown because the actual element type of b is string and not object.

Wenn ein Funktionsmember mit einem Parameter Array in der erweiterten Form aufgerufen wird, wird der Aufruf genau so verarbeitet, als ob ein Array Erstellungs Ausdruck mit einem Arrayinitialisierer (Array Erstellungs Ausdrücke) um die erweiterten Parameter eingefügt wurde.When a function member with a parameter array is invoked in its expanded form, the invocation is processed exactly as if an array creation expression with an array initializer (Array creation expressions) was inserted around the expanded parameters. Beispielsweise mit der DeklarationFor example, given the declaration

void F(int x, int y, params object[] args);

die folgenden Aufrufe der erweiterten Form der Methodethe following invocations of the expanded form of the method

F(10, 20);
F(10, 20, 30, 40);
F(10, 20, 1, "hello", 3.0);

genau entsprechencorrespond exactly to

F(10, 20, new object[] {});
F(10, 20, new object[] {30, 40});
F(10, 20, new object[] {1, "hello", 3.0});

Beachten Sie insbesondere, dass ein leeres Array erstellt wird, wenn keine Argumente für das Parameter Array angegeben werden.In particular, note that an empty array is created when there are zero arguments given for the parameter array.

Wenn Argumente von einem Funktionsmember mit entsprechenden optionalen Parametern ausgelassen werden, werden die Standardargumente der Deklaration des Funktions Members implizit übermittelt.When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. Da diese immer konstant sind, wirkt sich Ihre Auswertung nicht auf die Auswertungs Reihenfolge der restlichen Argumente aus.Because these are always constant, their evaluation will not impact the evaluation order of the remaining arguments.

TyprückschlussType inference

Wenn eine generische Methode ohne Angabe von Typargumenten aufgerufen wird, versucht ein Typrückschluss -Prozess, Typargumente für den Aufruf abzuleiten.When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. Das vorhanden sein des Typrückschlusses ermöglicht die Verwendung einer bequemeren Syntax zum Aufrufen einer generischen Methode und ermöglicht dem Programmierer, das Angeben von redundanten Typinformationen zu vermeiden.The presence of type inference allows a more convenient syntax to be used for calling a generic method, and allows the programmer to avoid specifying redundant type information. Beispielsweise mit der Methoden Deklaration:For example, given the method declaration:

class Chooser
{
    static Random rand = new Random();

    public static T Choose<T>(T first, T second) {
        return (rand.Next(2) == 0)? first: second;
    }
}

Es ist möglich, die Methode aufzurufen, Choose ohne explizit ein Typargument anzugeben:it is possible to invoke the Choose method without explicitly specifying a type argument:

int i = Chooser.Choose(5, 213);                 // Calls Choose<int>

string s = Chooser.Choose("foo", "bar");        // Calls Choose<string>

Durch den Typrückschluss werden die Typargumente int und string aus den Argumenten der Methode ermittelt.Through type inference, the type arguments int and string are determined from the arguments to the method.

Der Typrückschluss tritt als Teil der Bindungs Zeit Verarbeitung eines Methoden Aufrufs (Methodenaufrufe) auf und findet vor dem Schritt zur Überladungs Auflösung des Aufrufs statt.Type inference occurs as part of the binding-time processing of a method invocation (Method invocations) and takes place before the overload resolution step of the invocation. Wenn eine bestimmte Methoden Gruppe in einem Methodenaufruf angegeben wird und im Rahmen des Methoden aufruschlusses keine Typargumente angegeben werden, wird der Typrückschluss auf jede generische Methode in der Methoden Gruppe angewendet.When a particular method group is specified in a method invocation, and no type arguments are specified as part of the method invocation, type inference is applied to each generic method in the method group. Wenn der Typrückschluss erfolgreich ist, werden die Typargumente abgeleitet, um die Argument Typen für die nachfolgende Überladungs Auflösung zu bestimmen.If type inference succeeds, then the inferred type arguments are used to determine the types of arguments for subsequent overload resolution. Wenn die Überladungs Auflösung eine generische Methode als die aufzurufende Methode auswählt, werden die abgerufenen Typargumente als tatsächliche Typargumente für den Aufruf verwendet.If overload resolution chooses a generic method as the one to invoke, then the inferred type arguments are used as the actual type arguments for the invocation. Wenn der Typrückschluss für eine bestimmte Methode fehlschlägt, wird diese Methode nicht an der Überladungs Auflösung beteiligt.If type inference for a particular method fails, that method does not participate in overload resolution. Der Fehler beim Typrückschluss in und von sich führt nicht zu einem Bindungs Fehler.The failure of type inference, in and of itself, does not cause a binding-time error. Allerdings führt dies häufig zu einem Bindungs Fehler, wenn die Überladungs Auflösung dann keine anwendbaren Methoden findet.However, it often leads to a binding-time error when overload resolution then fails to find any applicable methods.

Wenn sich die angegebene Anzahl von Argumenten von der Anzahl der Parameter in der Methode unterscheidet, schlägt die Ableitung sofort fehl.If the supplied number of arguments is different than the number of parameters in the method, then inference immediately fails. Angenommen, die generische Methode hat die folgende Signatur:Otherwise, assume that the generic method has the following signature:

Tr M<X1,...,Xn>(T1 x1, ..., Tm xm)

Mit einem Methoden Aufrufder Form M(E1...Em) ist die Aufgabe des Typrückschlusses das Auffinden eindeutiger Typargumente S1...Sn für jeden der Typparameter, X1...Xn sodass der-Befehl M<S1...Sn>(E1...Em) gültig wird.With a method call of the form M(E1...Em) the task of type inference is to find unique type arguments S1...Sn for each of the type parameters X1...Xn so that the call M<S1...Sn>(E1...Em) becomes valid.

Während des Xi Abschlusses wird jeder Typparameter entweder mit einem bestimmten Typ korrigiert Si oder mit einem zugeordneten Satz von Begrenzungen nicht korrigiert .During the process of inference each type parameter Xi is either fixed to a particular type Si or unfixed with an associated set of bounds. Jede der Begrenzungen ist ein Typ T .Each of the bounds is some type T. Anfänglich wird jede Typvariable Xi mit einem leeren Satz von Begrenzungen nicht korrigiert.Initially each type variable Xi is unfixed with an empty set of bounds.

Der Typrückschluss findet in Phasen statt.Type inference takes place in phases. In jeder Phase wird versucht, Typargumente für weitere Typvariablen basierend auf den Ergebnissen der vorherigen Phase abzuleiten.Each phase will try to infer type arguments for more type variables based on the findings of the previous phase. In der ersten Phase werden einige anfängliche Rückschlüsse von Begrenzungen erstellt, während in der zweiten Phase Typvariablen für bestimmte Typen korrigiert und weitere Begrenzungen abgeleitet werden.The first phase makes some initial inferences of bounds, whereas the second phase fixes type variables to specific types and infers further bounds. Die zweite Phase muss möglicherweise mehrmals wiederholt werden.The second phase may have to be repeated a number of times.

Hinweis: Der Typrückschluss findet nicht nur statt, wenn eine generische Methode aufgerufen wird.Note: Type inference takes place not only when a generic method is called. Der Typrückschluss für die Konvertierung von Methoden Gruppen wird unter Typrückschluss für die Konvertierung von Methoden Gruppen beschrieben und der beste allgemeine Typ eines Satzes von Ausdrücken finden Sie unter Ermitteln des besten allgemeinen Typs eines Satzes von Ausdrücken.Type inference for conversion of method groups is described in Type inference for conversion of method groups and finding the best common type of a set of expressions is described in Finding the best common type of a set of expressions.

Die erste PhaseThe first phase

Für jedes der Methodenargumente Ei :For each of the method arguments Ei:

  • Wenn Ei eine anonyme Funktion ist, wird ein expliziter parametertyprückschluss (explizite parametertyprückschluss) von Ei zu TiIf Ei is an anonymous function, an explicit parameter type inference (Explicit parameter type inferences) is made from Ei to Ti
  • Andernfalls, wenn Ei einen-Typ aufweist U und xi ein value-Parameter ist, wird ein untergeordneter Daten Rückschluss von U bis erstellt Ti .Otherwise, if Ei has a type U and xi is a value parameter then a lower-bound inference is made from U to Ti.
  • Andernfalls, wenn Ei einen-Typ aufweist U und xi ein-oder-Parameter ist, ref out wird ein genauer Rückschluss von U auf vorgenommen Ti .Otherwise, if Ei has a type U and xi is a ref or out parameter then an exact inference is made from U to Ti.
  • Andernfalls wird kein Rückschluss für dieses Argument gemacht.Otherwise, no inference is made for this argument.

Die zweite PhaseThe second phase

Die zweite Phase verläuft wie folgt:The second phase proceeds as follows:

  • Alle unfixed -Typvariablen Xi , die nicht von abhängen (Abhängigkeit), Xj werden korrigiert (Korrektur).All unfixed type variables Xi which do not depend on (Dependence) any Xj are fixed (Fixing).
  • Wenn keine derartigen Typvariablen vorhanden sind, werden alle nicht fixierten Typvariablen Xi korrigiert , für die Folgendes gilt:If no such type variables exist, all unfixed type variables Xi are fixed for which all of the following hold:
    • Es ist mindestens eine Typvariable vorhanden Xj , von der abhängig ist. XiThere is at least one type variable Xj that depends on Xi
    • Xi weist einen nicht leeren Satz von Begrenzungen auf.Xi has a non-empty set of bounds
  • Wenn keine Typvariablen vorhanden sind und noch immer unfixe Typvariablen vorhanden sind, schlägt der Typrückschluss fehl.If no such type variables exist and there are still unfixed type variables, type inference fails.
  • Andernfalls ist der Typrückschluss erfolgreich, wenn keine weiteren unfixed -Typvariablen vorhanden sind.Otherwise, if no further unfixed type variables exist, type inference succeeds.
  • Andernfalls wird für alle Argumente Ei mit dem entsprechenden Parametertyp, Ti bei dem die Ausgabetypen (Ausgabetypen) nicht fixierte Typvariablen enthalten Xj , die Eingabetypen (Eingabetypen) jedoch nicht, ein Ausgabetyp Rückschluss (Ausgabetyp Rückschlüsse) von Ei auf erstellt Ti .Otherwise, for all arguments Ei with corresponding parameter type Ti where the output types (Output types) contain unfixed type variables Xj but the input types (Input types) do not, an output type inference (Output type inferences) is made from Ei to Ti. Die zweite Phase wird wiederholt.Then the second phase is repeated.

EingabetypenInput types

Wenn E eine Methoden Gruppe oder implizit typisierte anonyme Funktion ist und T ein Delegattyp oder ein Ausdrucks Strukturtyp ist, sind alle Parametertypen von T Eingabetypen vom E Typ T .If E is a method group or implicitly typed anonymous function and T is a delegate type or expression tree type then all the parameter types of T are input types of E with type T.

AusgabetypenOutput types

Wenn E eine Methoden Gruppe oder eine anonyme Funktion ist und T ein Delegattyp oder ein Ausdrucks Strukturtyp ist, ist der T Rückgabetyp von ein Ausgabetyp von E mit dem Typ T .If E is a method group or an anonymous function and T is a delegate type or expression tree type then the return type of T is an output type of E with type T.

HänDependence

Eine Variable vom Typ " unfixed " Xi ist direkt von einer Variablen vom Typ "unfixed" abhängig , Xj Wenn für ein Argument vom Ek Typ Tk Xj in einem Eingabetyp von Ek mit Type auftritt Tk und Xi in einem Ausgabetyp von Ek mit Type auftritt Tk .An unfixed type variable Xi depends directly on an unfixed type variable Xj if for some argument Ek with type Tk Xj occurs in an input type of Ek with type Tk and Xi occurs in an output type of Ek with type Tk.

Xjhängt von ab Xi , wenn direkt von oder abhängig ist, von der abhängig ist Xj Xi und abhängig ist Xi Xk Xk Xj .Xj depends on Xi if Xj depends directly on Xi or if Xi depends directly on Xk and Xk depends on Xj. Daher ist "hängt von" der transitiv, aber nicht reflexive Abschluss von "ist direkt abhängig".Thus "depends on" is the transitive but not reflexive closure of "depends directly on".

Ausschlüsse auf AusgabetypOutput type inferences

Ein ausgabetyprückschluss erfolgt auf folgende Weise von einem Ausdruck E zu einem Typ T :An output type inference is made from an expression E to a type T in the following way:

  • Wenn E eine anonyme Funktion mit einem abzurufenden Rückgabetyp U (Rückgabetyp abgeleitet) ist und T ein Delegattyp oder ein Ausdrucks Strukturtyp mit dem Rückgabetyp ist Tb , wird ein niedrigerer gebundener Typrückschluss (niedrigerer gebundener Rückschluss) von U bis vorgenommen Tb .If E is an anonymous function with inferred return type U (Inferred return type) and T is a delegate type or expression tree type with return type Tb, then a lower-bound inference (Lower-bound inferences) is made from U to Tb.
  • Andernfalls, wenn E eine Methoden Gruppe ist und T ein Delegattyp oder ein Ausdrucks Strukturtyp mit Parametertypen T1...Tk und dem Rückgabetyp ist Tb und die Überladungs Auflösung von E mit den-Typen T1...Tk eine einzelne Methode mit dem Rückgabetyp ergibt U , wird ein untergeordneter Daten Rückschluss von U in vorgenommen Tb .Otherwise, if E is a method group and T is a delegate type or expression tree type with parameter types T1...Tk and return type Tb, and overload resolution of E with the types T1...Tk yields a single method with return type U, then a lower-bound inference is made from U to Tb.
  • Andernfalls, wenn E ein Ausdruck mit dem Typ ist U , wird ein untergeordneter Daten Rückschluss von U bis erstellt T .Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T.
  • Andernfalls werden keine Rückschlüsse gemacht.Otherwise, no inferences are made.

Explizite Parametertyp RückschlüsseExplicit parameter type inferences

Ein expliziter Parameter-Typrückschluss erfolgt auf folgende Weise von einem Ausdruck E zu einem Typ T :An explicit parameter type inference is made from an expression E to a type T in the following way:

  • Wenn E eine explizit typisierte anonyme Funktion mit Parametertypen U1...Uk ist und T ein Delegattyp oder ein Ausdrucks Strukturtyp mit Parametertypen ist V1...Vk Ui , wird für jeden ein genauer Rück Schluss (exakte Rückschlüsse) von Ui auf das entsprechende-Objekt erstellt Vi .If E is an explicitly typed anonymous function with parameter types U1...Uk and T is a delegate type or expression tree type with parameter types V1...Vk then for each Ui an exact inference (Exact inferences) is made from Ui to the corresponding Vi.

Exakte RückschlüsseExact inferences

Eine genaue Ableitung von einem Typ U zu einem Typ V erfolgt wie folgt:An exact inference from a type U to a type V is made as follows:

  • Wenn V eine der unfixen ist Xi U , wird dem Satz der exakten Begrenzungen für hinzugefügt Xi .If V is one of the unfixed Xi then U is added to the set of exact bounds for Xi.

  • Andernfalls legt V1...Vk und U1...Uk fest, indem überprüft wird, ob eines der folgenden Fälle zutrifft:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • V ist ein Arraytyp V1[...] und U ist ein Arraytyp U1[...] desselben Rang.V is an array type V1[...] and U is an array type U1[...] of the same rank
    • V der Typ V1? und U ist der Typ. U1?V is the type V1? and U is the type U1?
    • V ist ein konstruierter Typ C<V1...Vk> und U ist ein konstruierter Typ. C<U1...Uk>V is a constructed type C<V1...Vk>and U is a constructed type C<U1...Uk>

    Wenn einer dieser Fälle zutrifft, erfolgt ein genauer Rückschluss von jedem Ui zum entsprechenden Vi .If any of these cases apply then an exact inference is made from each Ui to the corresponding Vi.

  • Andernfalls werden keine Rückschlüsse gemacht.Otherwise no inferences are made.

Unten gebundene RückschlüsseLower-bound inferences

Ein untergeordneter Daten Rückschluss von einem Typ U zu einem Typ V wird wie folgt erstellt:A lower-bound inference from a type U to a type V is made as follows:

  • Wenn V eine der nicht fixierten ist Xi U , wird der Gruppe der unteren Grenzen für hinzugefügt Xi .If V is one of the unfixed Xi then U is added to the set of lower bounds for Xi.

  • Andernfalls, wenn V der-Typ V1? und U der-Typ ist, U1? wird ein niedrigerer gebundener Rückschluss von U1 auf vorgenommen V1 .Otherwise, if V is the type V1?and U is the type U1? then a lower bound inference is made from U1 to V1.

  • Andernfalls legt U1...Uk und V1...Vk fest, indem überprüft wird, ob eines der folgenden Fälle zutrifft:Otherwise, sets U1...Uk and V1...Vk are determined by checking if any of the following cases apply:

    • V ist ein Arraytyp V1[...] und U ist ein Arraytyp U1[...] (oder ein Typparameter, dessen effektiver Basistyp ist U1[...] ) desselben Rang.V is an array type V1[...] and U is an array type U1[...] (or a type parameter whose effective base type is U1[...]) of the same rank

    • V ist eine von IEnumerable<V1> , ICollection<V1> oder, IList<V1> und U ist ein eindimensionaler Arraytyp U1[] (oder ein Typparameter, dessen effektiver Basistyp ist U1[] ).V is one of IEnumerable<V1>, ICollection<V1> or IList<V1> and U is a one-dimensional array type U1[](or a type parameter whose effective base type is U1[])

    • V ist eine konstruierte Klasse, eine Struktur, eine Schnittstelle oder ein Delegattyp, C<V1...Vk> und es gibt einen eindeutigen Typ, C<U1...Uk> sodass U (oder, wenn U ein Typparameter ist, die effektive Basisklasse oder ein beliebiger Member des effektiven Schnittstellen Satzes) mit identisch ist, von (direkt oder indirekt) erbt oder (direkt oder indirekt) implementiert C<U1...Uk> .V is a constructed class, struct, interface or delegate type C<V1...Vk> and there is a unique type C<U1...Uk> such that U (or, if U is a type parameter, its effective base class or any member of its effective interface set) is identical to, inherits from (directly or indirectly), or implements (directly or indirectly) C<U1...Uk>.

      (Die "Eindeutigkeits Einschränkung" bedeutet, dass in der Fall Schnittstelle C<T> {} class U: C<X>, C<Y> {} kein Rückschluss erfolgt, wenn von zu abgeleitet wird, U C<T> da U1 möglicherweise X oder ist Y .)(The "uniqueness" restriction means that in the case interface C<T> {} class U: C<X>, C<Y> {}, then no inference is made when inferring from U to C<T> because U1 could be X or Y.)

    Wenn einer dieser Fälle zutrifft, erfolgt ein Rückschluss von jedem Ui zum entsprechenden, Vi wie folgt:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Wenn Ui nicht bekannt ist, dass es sich um einen Verweistyp handelt, wird ein genauer Rückschluss gemacht.If Ui is not known to be a reference type then an exact inference is made
    • Andernfalls, wenn U ein Arraytyp ist, wird ein Rück Schluss mit niedrigerer Bindung erstellt.Otherwise, if U is an array type then a lower-bound inference is made
    • Andernfalls V C<V1...Vk> hängt der Rückschluss vom i-th Type-Parameter von ab C :Otherwise, if V is C<V1...Vk> then inference depends on the i-th type parameter of C:
      • Wenn Sie kovariant ist, wird ein Rück Schluss ausgelöst.If it is covariant then a lower-bound inference is made.
      • Wenn Sie kontra Variant ist, wird eine obere gebundene Ableitung vorgenommen.If it is contravariant then an upper-bound inference is made.
      • Wenn Sie invariante ist, wird ein genauer Rückschluss gemacht.If it is invariant then an exact inference is made.
  • Andernfalls werden keine Rückschlüsse gemacht.Otherwise, no inferences are made.

Obere gebundene RückschlüsseUpper-bound inferences

Eine obere gebundene Ableitung von einem Typ U zu einem Typ V wird wie folgt durchgeführt:An upper-bound inference from a type U to a type V is made as follows:

  • Wenn V eine der nicht fixierten ist Xi U , wird dem Satz von oberen Begrenzungen für hinzugefügt Xi .If V is one of the unfixed Xi then U is added to the set of upper bounds for Xi.

  • Andernfalls legt V1...Vk und U1...Uk fest, indem überprüft wird, ob eines der folgenden Fälle zutrifft:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • U ist ein Arraytyp U1[...] und V ist ein Arraytyp V1[...] desselben Rang.U is an array type U1[...] and V is an array type V1[...] of the same rank

    • U ist eine von IEnumerable<Ue> , ICollection<Ue> oder, IList<Ue> und V ist ein eindimensionaler Arraytyp. Ve[]U is one of IEnumerable<Ue>, ICollection<Ue> or IList<Ue> and V is a one-dimensional array type Ve[]

    • U der Typ U1? und V ist der Typ. V1?U is the type U1? and V is the type V1?

    • U ist eine konstruierte Klasse, Struktur, Schnittstelle oder Delegattyp C<U1...Uk> und V ist eine Klasse, Struktur, Schnittstelle oder ein Delegattyp, der mit identisch ist, von (direkt oder indirekt) erbt oder (direkt oder indirekt) einen eindeutigen Typ implementiert. C<V1...Vk>U is constructed class, struct, interface or delegate type C<U1...Uk> and V is a class, struct, interface or delegate type which is identical to, inherits from (directly or indirectly), or implements (directly or indirectly) a unique type C<V1...Vk>

      (Die "Eindeutigkeits Einschränkung" bedeutet, dass, wenn dies der Fall ist interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{} , kein Rückschluss erfolgt, wenn von zu abgeleitet wird C<U1> V<Q> .(The "uniqueness" restriction means that if we have interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}, then no inference is made when inferring from C<U1> to V<Q>. Rückschlüsse werden nicht von U1 entweder in oder aus vorgenommen X<Q> Y<Q> .)Inferences are not made from U1 to either X<Q> or Y<Q>.)

    Wenn einer dieser Fälle zutrifft, erfolgt ein Rückschluss von jedem Ui zum entsprechenden, Vi wie folgt:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Wenn Ui nicht bekannt ist, dass es sich um einen Verweistyp handelt, wird ein genauer Rückschluss gemacht.If Ui is not known to be a reference type then an exact inference is made
    • Andernfalls, wenn V ein Arraytyp ist, wird eine obere gebundene Ableitung vorgenommen.Otherwise, if V is an array type then an upper-bound inference is made
    • Andernfalls U C<U1...Uk> hängt der Rückschluss vom i-th Type-Parameter von ab C :Otherwise, if U is C<U1...Uk> then inference depends on the i-th type parameter of C:
      • Wenn Sie kovariant ist, wird eine obere gebundene Ableitung vorgenommen.If it is covariant then an upper-bound inference is made.
      • Wenn Sie kontra Variant ist, wird ein Rück Schluss festgestellt.If it is contravariant then a lower-bound inference is made.
      • Wenn Sie invariante ist, wird ein genauer Rückschluss gemacht.If it is invariant then an exact inference is made.
  • Andernfalls werden keine Rückschlüsse gemacht.Otherwise, no inferences are made.

Korrektur von Fixing

Eine Variable vom Typ " unfixed " Xi mit einem Satz von Begrenzungen ist wie folgt festgelegt :An unfixed type variable Xi with a set of bounds is fixed as follows:

  • Der Satz von Kandidaten Typen Uj beginnt als der Satz aller Typen im Satz von Begrenzungen für Xi .The set of candidate types Uj starts out as the set of all types in the set of bounds for Xi.
  • Anschließend untersuchen wir jede gebundene Grenze Xi : für jede exakte Grenze U Xi aller Typen Uj , die nicht identisch sind, U werden aus dem Kandidaten Satz entfernt.We then examine each bound for Xi in turn: For each exact bound U of Xi all types Uj which are not identical to U are removed from the candidate set. Für jede untere Grenze U Xi aller Typen Uj , auf die keine implizite Konvertierung von erfolgt, U werden aus dem Kandidaten Satz entfernt.For each lower bound U of Xi all types Uj to which there is not an implicit conversion from U are removed from the candidate set. Für jede obere Grenze U Xi aller Typen Uj , von denen keine implizite Konvertierung in vorhanden ist, U werden aus dem Kandidaten Satz entfernt.For each upper bound U of Xi all types Uj from which there is not an implicit conversion to U are removed from the candidate set.
  • Wenn es sich bei den verbleibenden Kandidaten Typen um Uj einen eindeutigen Typ handelt V , von dem eine implizite Konvertierung in alle anderen Kandidaten Typen erfolgt, dann Xi ist auf fest V .If among the remaining candidate types Uj there is a unique type V from which there is an implicit conversion to all the other candidate types, then Xi is fixed to V.
  • Andernfalls schlägt der Typrückschluss fehl.Otherwise, type inference fails.

Rückgabetyp abgeleitetInferred return type

Der abzurufende Rückgabetyp einer anonymen Funktion F wird bei der Typrückschluss-und Überladungs Auflösung verwendet.The inferred return type of an anonymous function F is used during type inference and overload resolution. Der zurückgegebene Rückgabetyp kann nur für eine anonyme Funktion bestimmt werden, bei der alle Parametertypen bekannt sind, da Sie entweder explizit angegeben werden, indem Sie durch eine anonyme Funktions Konvertierung bereitgestellt oder während des Typrückschlusses bei einem einschließenden generischen Methodenaufruf abgeleitet werden.The inferred return type can only be determined for an anonymous function where all parameter types are known, either because they are explicitly given, provided through an anonymous function conversion or inferred during type inference on an enclosing generic method invocation.

Der abhergelegte Ergebnistyp wird wie folgt bestimmt:The inferred result type is determined as follows:

  • Wenn der Text von F ein Ausdruck ist, der über einen-Typ verfügt, ist der herausgestellte Ergebnistyp von F der Typ dieses Ausdrucks.If the body of F is an expression that has a type, then the inferred result type of F is the type of that expression.
  • Wenn es sich bei dem Text von F um einen- Block handelt und der Satz von Ausdrücken in den-Anweisungen des Blocks return einen am besten allgemeinen Typ aufweist (suchen Sie T den am besten allgemeinen Typ eines Satzes von Ausdrücken), dann ist der abhergelegte Ergebnistyp von F T .If the body of F is a block and the set of expressions in the block's return statements has a best common type T (Finding the best common type of a set of expressions), then the inferred result type of F is T.
  • Andernfalls kann ein Ergebnistyp nicht für abgeleitet werden F .Otherwise, a result type cannot be inferred for F.

Der zurückgegebene Rückgabetyp wird wie folgt bestimmt:The inferred return type is determined as follows:

  • Wenn F Async ist und der Text von F entweder ein Ausdruck ist, der als Nothing (Ausdrucks Klassifizierungen) klassifiziert ist, oder ein Anweisungsblock, in dem keine Return-Anweisungen über Ausdrücke verfügen, ist der Rückschluss Rückgabetyp. System.Threading.Tasks.TaskIf F is async and the body of F is either an expression classified as nothing (Expression classifications), or a statement block where no return statements have expressions, the inferred return type is System.Threading.Tasks.Task
  • Wenn F Async ist und einen abhergelegten Ergebnistyp aufweist T , ist der Rückschluss Rückgabetyp System.Threading.Tasks.Task<T> .If F is async and has an inferred result type T, the inferred return type is System.Threading.Tasks.Task<T>.
  • Wenn F nicht Async ist und einen abhergelegten Ergebnistyp aufweist T , ist der Rückschluss Rückgabetyp T .If F is non-async and has an inferred result type T, the inferred return type is T.
  • Andernfalls kann kein Rückgabetyp für abgeleitet werden F .Otherwise a return type cannot be inferred for F.

Sehen Sie sich als Beispiel für den Typrückschluss mit anonymen Funktionen die Select in der-Klasse deklarierte Erweiterungsmethode an System.Linq.Enumerable :As an example of type inference involving anonymous functions, consider the Select extension method declared in the System.Linq.Enumerable class:

namespace System.Linq
{
    public static class Enumerable
    {
        public static IEnumerable<TResult> Select<TSource,TResult>(
            this IEnumerable<TSource> source,
            Func<TSource,TResult> selector)
        {
            foreach (TSource element in source) yield return selector(element);
        }
    }
}

Vorausgesetzt, System.Linq dass der Namespace mit einer using -Klausel importiert wurde und eine-Klasse Customer mit einer- Name Eigenschaft des Typs angegeben wurde string , kann die- Select Methode verwendet werden, um die Namen einer Kundenliste auszuwählen:Assuming the System.Linq namespace was imported with a using clause, and given a class Customer with a Name property of type string, the Select method can be used to select the names of a list of customers:

List<Customer> customers = GetCustomerList();
IEnumerable<string> names = customers.Select(c => c.Name);

Der Aufruf der Erweiterungsmethode (Erweiterungs Methodenaufrufe) von Select wird verarbeitet, indem der Aufruf in einen statischen Methodenaufruf umgeschrieben wird:The extension method invocation (Extension method invocations) of Select is processed by rewriting the invocation to a static method invocation:

IEnumerable<string> names = Enumerable.Select(customers, c => c.Name);

Da Typargumente nicht explizit angegeben wurden, wird der Typrückschluss verwendet, um die Typargumente abzuleiten.Since type arguments were not explicitly specified, type inference is used to infer the type arguments. Zuerst ist das- customers Argument mit dem-Parameter verknüpft und wird als source abgeleitet T Customer .First, the customers argument is related to the source parameter, inferring T to be Customer. Anschließend wird mit dem oben beschriebenen Prozess der anonymen Funktionstyp Ableitung der c Typ angegeben Customer , und der Ausdruck c.Name ist mit dem Rückgabetyp des selector Parameters verknüpft, S string der als abgeleitet wird.Then, using the anonymous function type inference process described above, c is given type Customer, and the expression c.Name is related to the return type of the selector parameter, inferring S to be string. Daher entspricht der Aufruf demThus, the invocation is equivalent to

Sequence.Select<Customer,string>(customers, (Customer c) => c.Name)

und das Ergebnis ist vom Typ IEnumerable<string> .and the result is of type IEnumerable<string>.

Im folgenden Beispiel wird veranschaulicht, wie der anonyme Funktionstyp Rückschluss das Eingeben von Typinformationen zwischen Argumenten in einem generischen Methodenaufruf zulässt.The following example demonstrates how anonymous function type inference allows type information to "flow" between arguments in a generic method invocation. Bei Angabe der-Methode:Given the method:

static Z F<X,Y,Z>(X value, Func<X,Y> f1, Func<Y,Z> f2) {
    return f2(f1(value));
}

Typrückschluss für den Aufruf:Type inference for the invocation:

double seconds = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds);

geht wie folgt vor: zuerst wird das-Argument mit "1:15:30" dem-Parameter verknüpft, der als value abgeleitet wird X string .proceeds as follows: First, the argument "1:15:30" is related to the value parameter, inferring X to be string. Anschließend erhält der-Parameter der ersten anonymen Funktion, s , den abzurufenden Typ string , und der Ausdruck TimeSpan.Parse(s) ist mit dem Rückgabetyp von verknüpft f1 , der als abgeleitet wird Y System.TimeSpan .Then, the parameter of the first anonymous function, s, is given the inferred type string, and the expression TimeSpan.Parse(s) is related to the return type of f1, inferring Y to be System.TimeSpan. Schließlich erhält der-Parameter der zweiten anonymen Funktion, t , den abzurufenden Typ System.TimeSpan , und der Ausdruck t.TotalSeconds ist mit dem Rückgabetyp von verknüpft, der als f2 abgeleitet wird Z double .Finally, the parameter of the second anonymous function, t, is given the inferred type System.TimeSpan, and the expression t.TotalSeconds is related to the return type of f2, inferring Z to be double. Daher ist das Ergebnis des auf-aufgabens vom Typ double .Thus, the result of the invocation is of type double.

Typrückschluss für die Konvertierung von Methoden GruppenType inference for conversion of method groups

Ähnlich wie bei Aufrufen von generischen Methoden muss der Typrückschluss auch angewendet werden, wenn eine Methoden Gruppe M , die eine generische Methode enthält, in einen angegebenen Delegattyp konvertiert wird D (Methoden Gruppen Konvertierungen).Similar to calls of generic methods, type inference must also be applied when a method group M containing a generic method is converted to a given delegate type D (Method group conversions). Bei Angabe einer MethodeGiven a method

Tr M<X1...Xn>(T1 x1 ... Tm xm)

und die Methoden Gruppe, die M dem Delegattyp zugewiesen wird, D ist die Aufgabe des Typrückschlusses, die Typargumente zu suchen S1...Sn , sodass der Ausdruck:and the method group M being assigned to the delegate type D the task of type inference is to find type arguments S1...Sn so that the expression:

M<S1...Sn>

wird mit kompatibel (Delegatdeklarationen) D .becomes compatible (Delegate declarations) with D.

Im Gegensatz zum Typrückschluss-Algorithmus für generische Methodenaufrufe gibt es in diesem Fall nur Argument Typen, keine Argument Ausdrücke.Unlike the type inference algorithm for generic method calls, in this case there are only argument types, no argument expressions. Insbesondere gibt es keine anonymen Funktionen und daher keinen Bedarf an mehreren Phasen des Inferenz.In particular, there are no anonymous functions and hence no need for multiple phases of inference.

Stattdessen werden alle Xi als nicht korrigiert betrachtet, und es wird ein Rück Schluss aus jedem Argumenttyp Uj von D auf den entsprechenden Parametertyp von erstellt Tj M .Instead, all Xi are considered unfixed, and a lower-bound inference is made from each argument type Uj of D to the corresponding parameter type Tj of M. Wenn für eine beliebige Grenze Xi keine Begrenzungen gefunden werden, schlägt der Typrückschluss fehl.If for any of the Xi no bounds were found, type inference fails. Andernfalls werden alle Xi entsprechend korrigiert Si , was das Ergebnis des Typrückschlusses ist.Otherwise, all Xi are fixed to corresponding Si, which are the result of type inference.

Ermitteln des am häufigsten verbreiteten Typs eines Satzes von AusdrückenFinding the best common type of a set of expressions

In einigen Fällen muss ein gemeinsamer Typ für einen Satz von Ausdrücken abgeleitet werden.In some cases, a common type needs to be inferred for a set of expressions. Insbesondere werden die Elementtypen von implizit typisierten Arrays und die Rückgabe Typen anonymer Funktionen mit Block Text auf diese Weise gefunden.In particular, the element types of implicitly typed arrays and the return types of anonymous functions with block bodies are found in this way.

Intuitiv, wenn ein Satz von Ausdrücken ist, E1...Em sollte dieser Rückschluss dem Aufrufen einer Methode entsprechen.Intuitively, given a set of expressions E1...Em this inference should be equivalent to calling a method

Tr M<X>(X x1 ... X xm)

mit den Ei As-Argumenten.with the Ei as arguments.

Genauer ist, dass der Rückschluss mit einer Variablen vom Typ " unfixed " beginnt X .More precisely, the inference starts out with an unfixed type variable X. Die Ausschlüsse auf Ausgabetyp werden dann von jedem Ei in vorgenommen X .Output type inferences are then made from each Ei to X. Schließlich X ist korrigiert , und wenn der Vorgang erfolgreich ist, ist der resultierende Typ S der resultierende am besten geeignete Typ für die Ausdrücke.Finally, X is fixed and, if successful, the resulting type S is the resulting best common type for the expressions. Wenn kein solcher S vorhanden ist, haben die Ausdrücke keinen besten allgemeinen Typ.If no such S exists, the expressions have no best common type.

ÜberladungsauflösungOverload resolution

Bei der Überladungs Auflösung handelt es sich um einen Bindungs zeitmechanismus zum Auswählen des besten Funktionsmembers, der beim Aufrufen einer Argumentliste und eines Satzes von Kandidaten Funktions Membern aufgerufen wird.Overload resolution is a binding-time mechanism for selecting the best function member to invoke given an argument list and a set of candidate function members. Die Überladungs Auflösung wählt den Funktions Member aus, der in den folgenden unterschiedlichen Kontexten in c# aufgerufen werden soll:Overload resolution selects the function member to invoke in the following distinct contexts within C#:

Jeder dieser Kontexte definiert den Satz von Kandidaten Funktionsmembern und die Liste der Argumente in der eigenen, eindeutigen Weise, wie in den oben aufgeführten Abschnitten ausführlich beschrieben.Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way, as described in detail in the sections listed above. Beispielsweise enthält der Satz von Kandidaten für einen Methodenaufruf keine Methoden, die als override (Member Suche) markiert sind, und Methoden in einer Basisklasse sind keine Kandidaten, wenn eine Methode in einer abgeleiteten Klasse anwendbar ist (MethodenAufrufe).For example, the set of candidates for a method invocation does not include methods marked override (Member lookup), and methods in a base class are not candidates if any method in a derived class is applicable (Method invocations).

Nachdem die Kandidaten Funktions Member und die Argumentliste identifiziert wurden, ist die Auswahl des besten Funktionsmembers in allen Fällen identisch:Once the candidate function members and the argument list have been identified, the selection of the best function member is the same in all cases:

  • In Anbetracht der Menge der anwendbaren Kandidaten Funktionsmember befindet sich das beste Funktionsmember in dieser Gruppe.Given the set of applicable candidate function members, the best function member in that set is located. Wenn die Menge nur ein Funktionsmember enthält, ist dieses Funktionsmember das beste Funktionsmember.If the set contains only one function member, then that function member is the best function member. Andernfalls ist das beste Funktionsmember der ein Funktionsmember, der besser als alle anderen Funktionsmember in Bezug auf die angegebene Argumentliste ist, vorausgesetzt, dass jeder Funktionsmember mit allen anderen Funktionsmembern verglichen wird, wobei die Regeln in einem besseren Funktionsmemberverwendet werden.Otherwise, the best function member is the one function member that is better than all other function members with respect to the given argument list, provided that each function member is compared to all other function members using the rules in Better function member. Wenn nicht genau ein Funktionsmember vorhanden ist, der besser als alle anderen Funktionsmember ist, dann ist der Funktionselement Aufruf mehrdeutig, und ein Bindungs Fehler tritt auf.If there is not exactly one function member that is better than all other function members, then the function member invocation is ambiguous and a binding-time error occurs.

In den folgenden Abschnitten wird die genaue Bedeutung der Begriffe *anwendbarer Funktionsmember _ und _ besseres Funktionsmember * definiert.The following sections define the exact meanings of the terms applicable function member _ and _better function member**.

Anwendbares FunktionsmemberApplicable function member

Ein Funktionsmember wird als anwendbares Funktionsmember in Bezug auf eine Argumentliste bezeichnet, A Wenn alle folgenden Punkte zutreffen:A function member is said to be an applicable function member with respect to an argument list A when all of the following are true:

  • Jedes Argument in A entspricht einem Parameter in der Deklaration des Funktions Members, wie in den entsprechenden Parameternbeschrieben, und jeder Parameter, dem kein Argument entspricht, ist ein optionaler Parameter.Each argument in A corresponds to a parameter in the function member declaration as described in Corresponding parameters, and any parameter to which no argument corresponds is an optional parameter.
  • Für jedes Argument in A ist der Parameter Übergabe Modus des Arguments (d. h. Value, ref oder out ) identisch mit dem Parameter Übergabe Modus des entsprechenden Parameters.For each argument in A, the parameter passing mode of the argument (i.e., value, ref, or out) is identical to the parameter passing mode of the corresponding parameter, and
    • für einen value-Parameter oder ein Parameter Array ist eine implizite Konvertierung (implizite Konvertierungen) vom-Argument in den Typ des entsprechenden Parameters vorhanden, oderfor a value parameter or a parameter array, an implicit conversion (Implicit conversions) exists from the argument to the type of the corresponding parameter, or
    • bei einem- ref oder- out Parameter ist der Typ des Arguments mit dem Typ des entsprechenden Parameters identisch.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter. Schließlich ref out ist der-Parameter oder der-Parameter ein Alias für das übergebenen Argument.After all, a ref or out parameter is an alias for the argument passed.

Bei einem Funktionsmember, der ein Parameter Array enthält, gilt Folgendes: Wenn das Funktionsmember durch die oben genannten Regeln anwendbar ist, wird es als anwendbar in der *normalen Form _ bezeichnet.For a function member that includes a parameter array, if the function member is applicable by the above rules, it is said to be applicable in its *normal form . Wenn ein Funktionsmember, der ein Parameter Array enthält, nicht in der normalen Form anwendbar ist, kann der Funktionsmember stattdessen in seiner Form " erweitert" ( *) angewendet werden:If a function member that includes a parameter array is not applicable in its normal form, the function member may instead be applicable in its _*expanded form**:

  • Das erweiterte Formular wird erstellt, indem das Parameter Array in der Deklaration des Funktions Members durch Null oder mehr Wert Parameter des Elementtyps des Parameter Arrays ersetzt wird, sodass die Anzahl der Argumente in der Argumentliste mit A der Gesamtanzahl der Parameter übereinstimmt.The expanded form is constructed by replacing the parameter array in the function member declaration with zero or more value parameters of the element type of the parameter array such that the number of arguments in the argument list A matches the total number of parameters. Wenn A weniger Argumente aufweist als die Anzahl fester Parameter in der Deklaration des Funktions Members, kann die erweiterte Form des Funktionsmembers nicht erstellt werden und ist daher nicht anwendbar.If A has fewer arguments than the number of fixed parameters in the function member declaration, the expanded form of the function member cannot be constructed and is thus not applicable.
  • Andernfalls ist das erweiterte Formular anwendbar, wenn für jedes Argument im A Parameter Übergabe Modus des Arguments mit dem Parameter Übergabe Modus des entsprechenden Parameters identisch ist, undOtherwise, the expanded form is applicable if for each argument in A the parameter passing mode of the argument is identical to the parameter passing mode of the corresponding parameter, and
    • bei einem Parameter mit festem Wert oder einem Wert Parameter, der durch die Erweiterung erstellt wurde, ist eine implizite Konvertierung (implizite Konvertierungen) vom Typ des Arguments in den Typ des entsprechenden Parameters vorhanden.for a fixed value parameter or a value parameter created by the expansion, an implicit conversion (Implicit conversions) exists from the type of the argument to the type of the corresponding parameter, or
    • bei einem- ref oder- out Parameter ist der Typ des Arguments mit dem Typ des entsprechenden Parameters identisch.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter.

Besseres FunktionsmemberBetter function member

Zum Ermitteln des besseren Funktionsmembers wird eine Liste der aus dem ausgebauten Argument enthaltenen Elemente erstellt, die nur die Argument Ausdrücke selbst in der Reihenfolge enthält, in der Sie in der ursprünglichen Argumentliste angezeigt werden.For the purposes of determining the better function member, a stripped-down argument list A is constructed containing just the argument expressions themselves in the order they appear in the original argument list.

Parameter Listen für jeden der Kandidaten Funktionsmember werden wie folgt erstellt:Parameter lists for each of the candidate function members are constructed in the following way:

  • Das erweiterte Formular wird verwendet, wenn das Funktionsmember nur in der erweiterten Form anwendbar ist.The expanded form is used if the function member was applicable only in the expanded form.
  • Optionale Parameter ohne entsprechende Argumente werden aus der Parameterliste entfernt.Optional parameters with no corresponding arguments are removed from the parameter list
  • Die Parameter werden neu angeordnet, sodass Sie an derselben Position wie das entsprechende Argument in der Argumentliste auftreten.The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.

Wenn eine Argumentliste A mit einem Satz von Argument Ausdrücken {E1, E2, ..., En} und zwei anwendbaren Funktionsmembern Mp und Mq mit Parametertypen {P1, P2, ..., Pn} und {Q1, Q2, ..., Qn} Mp definiert ist, wird ein besseres Funktionsmember definiert als Mq ifGiven an argument list A with a set of argument expressions {E1, E2, ..., En} and two applicable function members Mp and Mq with parameter types {P1, P2, ..., Pn} and {Q1, Q2, ..., Qn}, Mp is defined to be a better function member than Mq if

  • die implizite Konvertierung von in ist für jedes Ex Argument Qx nicht besser geeignet als bei der impliziten Konvertierung von Ex in Px .for each argument, the implicit conversion from Ex to Qx is not better than the implicit conversion from Ex to Px, and
  • für mindestens ein Argument ist die Konvertierung von Ex in Px besser als die Konvertierung von Ex in Qx .for at least one argument, the conversion from Ex to Px is better than the conversion from Ex to Qx.

Wenn Sie diese Auswertung durchführen, wenn Mp oder Mq in der erweiterten Form anwendbar ist Px , Qx verweist oder auf einen Parameter in der erweiterten Form der Parameterliste.When performing this evaluation, if Mp or Mq is applicable in its expanded form, then Px or Qx refers to a parameter in the expanded form of the parameter list.

Für den Fall, dass die Parametertyp Sequenzen  {P1, P2, ..., Pn} und {Q1, Q2, ..., Qn} äquivalent sind (d. h. Pi , jede verfügt über eine Identitäts Konvertierung in die entsprechende Qi ), werden die folgenden Regeln zum Durchbrechen von Regeln angewendet, um den besseren Funktionsmember zu ermitteln.In case the parameter type sequences {P1, P2, ..., Pn} and {Q1, Q2, ..., Qn} are equivalent (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.

  • Wenn Mp eine nicht generische Methode ist und Mq eine generische Methode ist, dann Mp ist besser als Mq .If Mp is a non-generic method and Mq is a generic method, then Mp is better than Mq.
  • Andernfalls ist, wenn Mp in der normalen Form anwendbar und Mq ein params -Array hat und nur in der erweiterten Form anwendbar ist, Mp besser als Mq .Otherwise, if Mp is applicable in its normal form and Mq has a params array and is applicable only in its expanded form, then Mp is better than Mq.
  • Andernfalls ist, wenn Mp mehr deklarierte Parameter als aufweist Mq , Mp besser als Mq .Otherwise, if Mp has more declared parameters than Mq, then Mp is better than Mq. Dies kann vorkommen, wenn beide Methoden über params Arrays verfügen und nur in ihren erweiterten Formularen anwendbar sind.This can occur if both methods have params arrays and are applicable only in their expanded forms.
  • Andernfalls, wenn alle Parameter von Mp ein entsprechendes Argument aufweisen, während Standardargumente mindestens einen optionalen Parameter in ersetzen müssen, Mq Mp ist besser als Mq .Otherwise if all parameters of Mp have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in Mq then Mp is better than Mq.
  • Wenn andernfalls Mp spezifischere Parametertypen als aufweist Mq , dann Mp ist besser als Mq .Otherwise, if Mp has more specific parameter types than Mq, then Mp is better than Mq. {R1, R2, ..., Rn}Stellen Sie {S1, S2, ..., Sn} die nicht instanziierten und nicht erweiterten Parametertypen von Mp und dar Mq .Let {R1, R2, ..., Rn} and {S1, S2, ..., Sn} represent the uninstantiated and unexpanded parameter types of Mp and Mq. Mpdie Parametertypen sind spezifischer als, Mq Wenn für jeden Parameter Rx nicht weniger spezifisch als ist, Sx und für mindestens einen Parameter Rx eher spezifischer als Sx :Mp's parameter types are more specific than Mq's if, for each parameter, Rx is not less specific than Sx, and, for at least one parameter, Rx is more specific than Sx:
    • Ein Typparameter ist weniger spezifisch als ein nicht-Typparameter.A type parameter is less specific than a non-type parameter.
    • Ein konstruierter Typ ist rekursiv spezifischer als ein anderer konstruierter Typ (mit der gleichen Anzahl von Typargumenten), wenn mindestens ein Typargument spezifischer ist und kein Typargument weniger spezifisch als das entsprechende Typargument in der anderen ist.Recursively, a constructed type is more specific than another constructed type (with the same number of type arguments) if at least one type argument is more specific and no type argument is less specific than the corresponding type argument in the other.
    • Ein Arraytyp ist spezifischer als ein anderer Arraytyp (mit der gleichen Anzahl von Dimensionen), wenn der Elementtyp des ersten spezifischeren ist als der Elementtyp der zweiten.An array type is more specific than another array type (with the same number of dimensions) if the element type of the first is more specific than the element type of the second.
  • Wenn ein Member ein nicht gesperrter Operator und der andere ein gesperrter Operator ist, ist der nicht--gesteigerte-Operator besser.Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.
  • Andernfalls ist keines der Funktionsmember besser.Otherwise, neither function member is better.

Bessere Konvertierung von AusdrückenBetter conversion from expression

Wenn eine implizite Konvertierung, C1 die von einem Ausdruck E in einen-Typ konvertiert T1 wird, und eine implizite Konvertierung, C2 die von einem Ausdruck E in einen-Typ konvertiert wird T2 , C1 eine bessere Konvertierung ist, als C2 Wenn E nicht genau übereinstimmt T2 und mindestens einer der folgenden Punkte enthält:Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that converts from an expression E to a type T2, C1 is a better conversion than C2 if E does not exactly match T2 and at least one of the following holds:

Exakt übereinstimmender AusdruckExactly matching Expression

Bei einem Ausdruck E und einem Typ T E stimmt genau überein, T Wenn eine der folgenden Punkte Folgendes enthält:Given an expression E and a type T, E exactly matches T if one of the following holds:

  • E weist einen Typ S auf, und eine Identitäts Konvertierung ist von S zu TE has a type S, and an identity conversion exists from S to T
  • E ist eine anonyme Funktion, T ist entweder ein Delegattyp D oder ein Ausdrucks Strukturtyp, Expression<D> und einer der folgenden enthält Folgendes:E is an anonymous function, T is either a delegate type D or an expression tree type Expression<D> and one of the following holds:
    • Für wird ein abherüberder Rückgabetyp X E im Kontext der Parameterliste D (abgeleitet Rückgabetyp) und eine Identitäts Konvertierung von in X den Rückgabetyp DAn inferred return type X exists for E in the context of the parameter list of D (Inferred return type), and an identity conversion exists from X to the return type of D
    • Entweder E ist nicht Async und D hat einen Rückgabetyp oder ist asynchron Y E und D verfügt über einen Rückgabetyp Task<Y> , und eine der folgenden Punkte enthält:Either E is non-async and D has a return type Y or E is async and D has a return type Task<Y>, and one of the following holds:
      • Der Text von E ist ein Ausdruck, der genau übereinstimmt. YThe body of E is an expression that exactly matches Y
      • Der Text von E ist ein Anweisungsblock, in dem jede Return-Anweisung einen Ausdruck zurückgibt, der genau übereinstimmt YThe body of E is a statement block where every return statement returns an expression that exactly matches Y

Besseres Konvertierungs ZielBetter conversion target

Bei zwei verschiedenen Typen T1 und T2 T1 ist ein besseres Konvertierungs Ziel als, T2 Wenn keine implizite Konvertierung von T2 in vorhanden ist T1 , und mindestens eine der folgenden Werte enthält:Given two different types T1 and T2, T1 is a better conversion target than T2 if no implicit conversion from T2 to T1 exists, and at least one of the following holds:

  • Eine implizite Konvertierung von T1 in ist T2 vorhanden.An implicit conversion from T1 to T2 exists
  • T1 ist entweder ein Delegattyp D1 oder ein Ausdrucks bauentyp Expression<D1> , T2 ist entweder ein Delegattyp D2 oder ein Ausdrucks bauentyp Expression<D2> , D1 hat einen Rückgabetyp S1 und eine der folgenden Punkte:T1 is either a delegate type D1 or an expression tree type Expression<D1>, T2 is either a delegate type D2 or an expression tree type Expression<D2>, D1 has a return type S1 and one of the following holds:
    • D2 ist void-RückgabeD2 is void returning
    • D2 hat einen Rückgabetyp S2 und S1 ist ein besseres Konvertierungs Ziel als S2D2 has a return type S2, and S1 is a better conversion target than S2
  • T1 ist Task<S1> , T2 ist Task<S2> , und S1 ist ein besseres Konvertierungs Ziel als S2T1 is Task<S1>, T2 is Task<S2>, and S1 is a better conversion target than S2
  • T1 ist S1 oder, wobei ein ganzzahliger Typ mit Vorzeichen ist S1? S1 , und T2 ist oder, wenn ein ganzzahliger S2 S2? S2 Typ ohne Vorzeichen ist.T1 is S1 or S1? where S1 is a signed integral type, and T2 is S2 or S2? where S2 is an unsigned integral type. Dies betrifft insbesondere:Specifically:
    • S1 ist sbyte S2 , und ist byte , ushort , uint oder ulongS1 is sbyte and S2 is byte, ushort, uint, or ulong
    • S1 ist short S2 , und ist ushort , uint oder. ulongS1 is short and S2 is ushort, uint, or ulong
    • S1 ist int S2 , und ist uint , oder ulongS1 is int and S2 is uint, or ulong
    • S1 ist, long und S2 ist ulongS1 is long and S2 is ulong

Überladen in generischen KlassenOverloading in generic classes

Obwohl Signaturen wie deklariert eindeutig sein müssen, ist es möglich, dass die Ersetzung von Typargumenten zu identischen Signaturen führt.While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. In solchen Fällen werden die oben genannten Regeln der Überladungs Auflösung über den spezifischsten Member ausgewählt.In such cases, the tie-breaking rules of overload resolution above will pick the most specific member.

Die folgenden Beispiele zeigen über Ladungen, die gemäß dieser Regel gültig und ungültig sind:The following examples show overloads that are valid and invalid according to this rule:

interface I1<T> {...}

interface I2<T> {...}

class G1<U>
{
    int F1(U u);                  // Overload resolution for G<int>.F1
    int F1(int i);                // will pick non-generic

    void F2(I1<U> a);             // Valid overload
    void F2(I2<U> a);
}

class G2<U,V>
{
    void F3(U u, V v);            // Valid, but overload resolution for
    void F3(V v, U u);            // G2<int,int>.F3 will fail

    void F4(U u, I1<V> v);        // Valid, but overload resolution for    
    void F4(I1<V> v, U u);        // G2<I1<int>,int>.F4 will fail

    void F5(U u1, I1<V> v2);      // Valid overload
    void F5(V v1, U u2);

    void F6(ref U u);             // valid overload
    void F6(out V v);
}

Kompilierzeit Überprüfung der Auflösung dynamischer ÜberladungenCompile-time checking of dynamic overload resolution

Bei den meisten dynamisch gebundenen Vorgängen ist der Satz möglicher Kandidaten für die Auflösung zur Kompilierzeit nicht bekannt.For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. In bestimmten Fällen ist der Kandidaten Satz jedoch zum Zeitpunkt der Kompilierung bekannt:In certain cases, however the candidate set is known at compile-time:

  • Statische Methodenaufrufe mit dynamischen ArgumentenStatic method calls with dynamic arguments
  • Instanzmethodenaufrufe, bei denen der Empfänger kein dynamischer Ausdruck istInstance method calls where the receiver is not a dynamic expression
  • Indexer-Aufrufe, bei denen der Empfänger kein dynamischer Ausdruck istIndexer calls where the receiver is not a dynamic expression
  • Konstruktoraufrufe mit dynamischen ArgumentenConstructor calls with dynamic arguments

In diesen Fällen wird für jeden Kandidaten eine beschränkte Kompilierzeit Überprüfung durchgeführt, um festzustellen, ob eine dieser Vorgänge möglicherweise zur Laufzeit angewendet werden könnte. Diese Überprüfung umfasst die folgenden Schritte:In these cases a limited compile-time check is performed for each candidate to see if any of them could possibly apply at run-time.This check consists of the following steps:

  • Partieller Typrückschluss: alle Typargumente, die nicht direkt oder indirekt von einem Argument des Typs abhängen, werden dynamic mithilfe der Regeln des Typrückschlussesabgeleitet.Partial type inference: Any type argument that does not depend directly or indirectly on an argument of type dynamic is inferred using the rules of Type inference. Die übrigen Typargumente sind unbekannt.The remaining type arguments are unknown.
  • Partielle Anwendbarkeit der Anwendbarkeit: die Anwendbarkeit wird gemäß dem anwendbaren Funktionsmemberüberprüft, wobei Parameter, deren Typen unbekannt sind, ignoriert werden.Partial applicability check: Applicability is checked according to Applicable function member, but ignoring parameters whose types are unknown.
  • Wenn kein Kandidat diesen Test durchläuft, tritt ein Kompilierzeitfehler auf.If no candidate passes this test, a compile-time error occurs.

Funktionselement AufrufFunction member invocation

In diesem Abschnitt wird der Prozess beschrieben, der zur Laufzeit ausgeführt wird, um einen bestimmten Funktionsmember aufzurufen.This section describes the process that takes place at run-time to invoke a particular function member. Es wird davon ausgegangen, dass ein Bindungs Zeit Prozess bereits den aufzurufenden Member ermittelt hat, möglicherweise durch Anwenden der Überladungs Auflösung auf einen Satz von Kandidaten Funktionsmembern.It is assumed that a binding-time process has already determined the particular member to invoke, possibly by applying overload resolution to a set of candidate function members.

Um den Aufrufprozess zu beschreiben, werden Funktionsmember in zwei Kategorien unterteilt:For purposes of describing the invocation process, function members are divided into two categories:

  • Statische Funktionsmember.Static function members. Dabei handelt es sich um Instanzkonstruktoren, statische Methoden, statische Eigenschaftenaccessoren und benutzerdefinierte Operatoren.These are instance constructors, static methods, static property accessors, and user-defined operators. Statische Funktionsmember sind immer nicht virtuell.Static function members are always non-virtual.
  • Instanzfunktionsmember.Instance function members. Dabei handelt es sich um Instanzmethoden, Accessoren für Instanzeigenschaften und Indexer-Accessoren.These are instance methods, instance property accessors, and indexer accessors. Instanzfunktionsmember sind entweder nicht virtuell oder virtuell und werden immer für eine bestimmte Instanz aufgerufen.Instance function members are either non-virtual or virtual, and are always invoked on a particular instance. Die Instanz wird durch einen Instanzausdruck berechnet und kann innerhalb des Funktionsmembers als this (dieser Zugriff) aufgerufen werden.The instance is computed by an instance expression, and it becomes accessible within the function member as this (This access).

Die Lauf Zeit Verarbeitung eines Funktionsmember-aufzurufenden besteht aus den folgenden Schritten, wobei M der Funktionsmember ist und, wenn M ein Instanzmember ist, E der Instanzausdruck ist:The run-time processing of a function member invocation consists of the following steps, where M is the function member and, if M is an instance member, E is the instance expression:

  • Wenn M ein statischer Funktionsmember ist:If M is a static function member:

    • Die Argumentliste wird entsprechend der Beschreibung in den Argumentlistenausgewertet.The argument list is evaluated as described in Argument lists.
    • M wird aufgerufen.M is invoked.
  • Wenn M ein Instanzfunktionsmember ist, der in einem value_type deklariert ist:If M is an instance function member declared in a value_type:

    • E wird ausgewertet.E is evaluated. Wenn diese Auswertung eine Ausnahme verursacht, werden keine weiteren Schritte ausgeführt.If this evaluation causes an exception, then no further steps are executed.
    • Wenn E nicht als Variable klassifiziert ist, wird eine temporäre lokale Variable vom E Typ erstellt und der Wert von der E Variablen zugewiesen.If E is not classified as a variable, then a temporary local variable of E's type is created and the value of E is assigned to that variable. E wird dann als Verweis auf diese temporäre lokale Variable neu klassifiziert.E is then reclassified as a reference to that temporary local variable. Der Zugriff auf die temporäre Variable ist als this innerhalb M möglich, aber nicht auf andere Weise.The temporary variable is accessible as this within M, but not in any other way. Folglich kann der Aufrufer nur dann, wenn E eine echte Variable ist, die Änderungen beobachten, die M an vornimmt this .Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.
    • Die Argumentliste wird entsprechend der Beschreibung in den Argumentlistenausgewertet.The argument list is evaluated as described in Argument lists.
    • M wird aufgerufen.M is invoked. Die Variable, auf die verweist, E wird zur Variablen, auf die verweist this .The variable referenced by E becomes the variable referenced by this.
  • Wenn M ein Instanzfunktionsmember ist, der in einem reference_type deklariert ist:If M is an instance function member declared in a reference_type:

    • E wird ausgewertet.E is evaluated. Wenn diese Auswertung eine Ausnahme verursacht, werden keine weiteren Schritte ausgeführt.If this evaluation causes an exception, then no further steps are executed.
    • Die Argumentliste wird entsprechend der Beschreibung in den Argumentlistenausgewertet.The argument list is evaluated as described in Argument lists.
    • Wenn der Typ von E ein value_type ist, wird eine Boxing-Konvertierung (Boxing-Konvertierungen) ausgeführt, um E Sie in den-Typ zu konvertieren object , und E wird object in den folgenden Schritten als Typ betrachtet.If the type of E is a value_type, a boxing conversion (Boxing conversions) is performed to convert E to type object, and E is considered to be of type object in the following steps. In diesem Fall M kann nur ein Member von sein System.Object .In this case, M could only be a member of System.Object.
    • Der Wert von E wird als gültig geprüft.The value of E is checked to be valid. Wenn der Wert von E ist null , wird eine ausgelöst, System.NullReferenceException und es werden keine weiteren Schritte ausgeführt.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Die aufzurufende Funktionsmember-Implementierung wird bestimmt:The function member implementation to invoke is determined:
      • Wenn der Bindungstyp von E eine Schnittstelle ist, ist das aufzurufende Funktionsmember die Implementierung von, die M von dem Lauf Zeittyp der Instanz bereitgestellt wird, auf die von verwiesen wird E .If the binding-time type of E is an interface, the function member to invoke is the implementation of M provided by the run-time type of the instance referenced by E. Dieses Funktionsmember wird bestimmt, indem die Schnittstellen Zuordnungs Regeln (Schnittstellen Zuordnung) angewendet werden, um die Implementierung von zu bestimmen, die M durch den Lauf Zeittyp der Instanz bereitgestellt wird, auf die verweist E .This function member is determined by applying the interface mapping rules (Interface mapping) to determine the implementation of M provided by the run-time type of the instance referenced by E.
      • Andernfalls, wenn M ein virtuelles Funktionsmember ist, ist das aufzurufende Funktionsmember die Implementierung von, die M vom Lauf Zeittyp der Instanz bereitgestellt wird, auf die von verwiesen wird E .Otherwise, if M is a virtual function member, the function member to invoke is the implementation of M provided by the run-time type of the instance referenced by E. Dieses Funktionsmember wird festgelegt, indem die Regeln zum Bestimmen der am weitesten abgeleiteten Implementierung (virtuelle Methoden) von M in Bezug auf den Lauf Zeittyp der Instanz, auf die von verwiesen wird, angewendet werden E .This function member is determined by applying the rules for determining the most derived implementation (Virtual methods) of M with respect to the run-time type of the instance referenced by E.
      • Andernfalls M ist ein nicht virtuelles Funktionsmember, und der aufzurufende Funktionsmember ist M selbst.Otherwise, M is a non-virtual function member, and the function member to invoke is M itself.
    • Die im obigen Schritt festgelegte Funktionsmember-Implementierung wird aufgerufen.The function member implementation determined in the step above is invoked. Das Objekt, auf das verweist, E wird das Objekt, auf das verweist this .The object referenced by E becomes the object referenced by this.

Aufrufe für geboxte InstanzenInvocations on boxed instances

Ein Funktionsmember, der in einem value_type implementiert ist, kann über eine geachtelte Instanz von aufgerufen werden, die in den folgenden Situationen value_type :A function member implemented in a value_type can be invoked through a boxed instance of that value_type in the following situations:

  • Wenn das Funktionsmember eine einer Methode ist, die override vom-Typ geerbt wurde, object und wird durch einen Instanzausdruck vom Typ aufgerufen object .When the function member is an override of a method inherited from type object and is invoked through an instance expression of type object.
  • Wenn das Funktionsmember eine Implementierung eines Schnittstellenfunktionsmembers ist und durch einen Instanzausdruck eines INTERFACE_TYPE aufgerufen wird.When the function member is an implementation of an interface function member and is invoked through an instance expression of an interface_type.
  • Wenn der Funktionsmember durch einen Delegaten aufgerufen wird.When the function member is invoked through a delegate.

In diesen Fällen wird die geschachtelte Instanz als eine Variable des value_type enthalten, und diese Variable wird zur Variablen, auf die this innerhalb des Funktionselement aufzurufenden verwiesen wird.In these situations, the boxed instance is considered to contain a variable of the value_type, and this variable becomes the variable referenced by this within the function member invocation. Dies bedeutet insbesondere, dass beim Aufrufen eines Funktionsmembers für eine geachtelte Instanz der Funktionsmember den in der geboxten Instanz enthaltenen Wert ändern kann.In particular, this means that when a function member is invoked on a boxed instance, it is possible for the function member to modify the value contained in the boxed instance.

Primäre AusdrückePrimary expressions

Primäre Ausdrücke enthalten die einfachsten Formen von Ausdrücken.Primary expressions include the simplest forms of expressions.

primary_expression
    : primary_no_array_creation_expression
    | array_creation_expression
    ;

primary_no_array_creation_expression
    : literal
    | interpolated_string_expression
    | simple_name
    | parenthesized_expression
    | member_access
    | invocation_expression
    | element_access
    | this_access
    | base_access
    | post_increment_expression
    | post_decrement_expression
    | object_creation_expression
    | delegate_creation_expression
    | anonymous_object_creation_expression
    | typeof_expression
    | checked_expression
    | unchecked_expression
    | default_value_expression
    | nameof_expression
    | anonymous_method_expression
    | primary_no_array_creation_expression_unsafe
    ;

Primäre Ausdrücke werden zwischen array_creation_expression s und primary_no_array_creation_expression s aufgeteilt.Primary expressions are divided between array_creation_expression s and primary_no_array_creation_expression s. Wenn Sie Array-Creation-Expression auf diese Weise behandeln, anstatt sie zusammen mit den anderen einfachen Ausdrucks Formularen aufzulisten, ermöglicht die Grammatik, potenziell verwirrenden Code, wie z. b.Treating array-creation-expression in this way, rather than listing it along with the other simple expression forms, enables the grammar to disallow potentially confusing code such as

object o = new int[3][1];

der andernfalls interpretiert werden würde.which would otherwise be interpreted as

object o = (new int[3])[1];

LiteraleLiterals

Eine primary_expression , die aus einem Literalzeichen (Literale) besteht, wird als Wert klassifiziert.A primary_expression that consists of a literal (Literals) is classified as a value.

Interpolierte ZeichenfolgenInterpolated strings

Ein interpolated_string_expression besteht aus einem $ Vorzeichen, gefolgt von einem regulären oder ausführlichen Zeichenfolgenliteral, bei dem die durch und getrennten Lücken, die { } Ausdrücke und Formatierungs Spezifikationen einschließen.An interpolated_string_expression consists of a $ sign followed by a regular or verbatim string literal, wherein holes, delimited by { and }, enclose expressions and formatting specifications. Ein interintererter Zeichen folgen Ausdruck ist das Ergebnis einer interpolated_string_literal , die in einzelne Token unterteilt wurde, wie in interpoliert-Zeichenfolgenliteralenbeschrieben.An interpolated string expression is the result of an interpolated_string_literal that has been broken up into individual tokens, as described in Interpolated string literals.

interpolated_string_expression
    : '$' interpolated_regular_string
    | '$' interpolated_verbatim_string
    ;

interpolated_regular_string
    : interpolated_regular_string_whole
    | interpolated_regular_string_start interpolated_regular_string_body interpolated_regular_string_end
    ;

interpolated_regular_string_body
    : interpolation (interpolated_regular_string_mid interpolation)*
    ;

interpolation
    : expression
    | expression ',' constant_expression
    ;

interpolated_verbatim_string
    : interpolated_verbatim_string_whole
    | interpolated_verbatim_string_start interpolated_verbatim_string_body interpolated_verbatim_string_end
    ;

interpolated_verbatim_string_body
    : interpolation (interpolated_verbatim_string_mid interpolation)+
    ;

Der constant_expression in einer Interpolations muss über eine implizite Konvertierung in verfügen int .The constant_expression in an interpolation must have an implicit conversion to int.

Ein interpolated_string_expression wird als Wert klassifiziert.An interpolated_string_expression is classified as a value. Wenn Sie sofort in System.IFormattable oder System.FormattableString mit einer impliziten interkrelierten Zeichen folgen Konvertierung (implizite interpoliert-Zeichen folgen Konvertierungen) konvertiert wird, hat der interpoliert Zeichen folgen Ausdruck diesen Typ.If it is immediately converted to System.IFormattable or System.FormattableString with an implicit interpolated string conversion (Implicit interpolated string conversions), the interpolated string expression has that type. Andernfalls weist Sie den-Typ auf string .Otherwise, it has the type string.

Wenn der Typ einer interinterpolierten Zeichenfolge System.IFormattable oder ist System.FormattableString , ist die Bedeutung ein-Rückruf System.Runtime.CompilerServices.FormattableStringFactory.Create .If the type of an interpolated string is System.IFormattable or System.FormattableString, the meaning is a call to System.Runtime.CompilerServices.FormattableStringFactory.Create. Wenn der Typ ist string , ist die Bedeutung des Ausdrucks ein-Rückruf string.Format .If the type is string, the meaning of the expression is a call to string.Format. In beiden Fällen besteht die Argumentliste des Aufrufes aus einem Format Zeichenfolgenliteralzeichen mit Platzhaltern für jede interpolung und einem Argument für jeden Ausdruck, der den Platzhaltern entspricht.In both cases, the argument list of the call consists of a format string literal with placeholders for each interpolation, and an argument for each expression corresponding to the place holders.

Der Format Zeichenfolgenliterale wird wie folgt erstellt, wobei N die Anzahl der Interpolationen in der interpolated_string_expression ist:The format string literal is constructed as follows, where N is the number of interpolations in the interpolated_string_expression:

  • Wenn ein interpolated_regular_string_whole oder eine interpolated_verbatim_string_whole auf das $ Vorzeichen folgt, ist das Format Zeichenfolgenliteralzeichen das Token.If an interpolated_regular_string_whole or an interpolated_verbatim_string_whole follows the $ sign, then the format string literal is that token.
  • Andernfalls besteht das Format Zeichenfolgenliterale aus folgendem:Otherwise, the format string literal consists of:
    • Zuerst die interpolated_regular_string_start oder interpolated_verbatim_string_startFirst the interpolated_regular_string_start or interpolated_verbatim_string_start
    • Dann für jede Zahl I von 0 zu N-1 :Then for each number I from 0 to N-1:
      • Die Dezimal Darstellung von. IThe decimal representation of I
      • Wenn die entsprechende Interpolations constant_expression ist, dann ein , (Komma), gefolgt von der Dezimal Darstellung des Werts des constant_expressionThen, if the corresponding interpolation has a constant_expression, a , (comma) followed by the decimal representation of the value of the constant_expression
      • Anschließend werden die interpolated_regular_string_mid, die interpolated_regular_string_end, interpolated_verbatim_string_mid oder interpolated_verbatim_string_end unmittelbar auf die entsprechende interpolung folgt.Then the interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid or interpolated_verbatim_string_end immediately following the corresponding interpolation.

Die nachfolgenden Argumente sind einfach die Ausdrücke aus den Interpolationen (sofern vorhanden), in der richtigen Reihenfolge.The subsequent arguments are simply the expressions from the interpolations (if any), in order.

TODO: Beispiele.TODO: examples.

Einfache NamenSimple names

Eine Simple_name besteht aus einem Bezeichner, optional gefolgt von einer Typargument Liste:A simple_name consists of an identifier, optionally followed by a type argument list:

simple_name
    : identifier type_argument_list?
    ;

Ein Simple_name weist entweder das Formular I oder das Format auf I<A1,...,Ak> , wobei I ein einzelner Bezeichner und <A1,...,Ak> ein optionaler type_argument_list ist.A simple_name is either of the form I or of the form I<A1,...,Ak>, where I is a single identifier and <A1,...,Ak> is an optional type_argument_list. Wenn keine type_argument_list angegeben ist, sollten K Sie den Wert 0 (null) angeben.When no type_argument_list is specified, consider K to be zero. Die Simple_name wird wie folgt ausgewertet und klassifiziert:The simple_name is evaluated and classified as follows:

  • Wenn K 0 (null) ist und die Simple_name in einem- Block angezeigt wird, und wenn der Block(oder ein einschließender Block) der Deklaration der lokalen Variablen Deklaration (Deklarationen) eine lokale Variable, einen Parameter oder eine Konstante mit Namen enthält  I , verweist der Simple_name auf diese lokale Variable, den Parameter oder die Konstante und wird als Variable oder Wert klassifiziert.If K is zero and the simple_name appears within a block and if the block's (or an enclosing block's) local variable declaration space (Declarations) contains a local variable, parameter or constant with name I, then the simple_name refers to that local variable, parameter or constant and is classified as a variable or value.

  • Wenn K 0 (null) ist und die Simple_name im Text einer generischen Methoden Deklaration angezeigt wird und diese Deklaration einen Typparameter mit dem Namen enthält  I , verweist der Simple_name auf diesen Typparameter.If K is zero and the simple_name appears within the body of a generic method declaration and if that declaration includes a type parameter with name I, then the simple_name refers to that type parameter.

  • Andernfalls für jeden Instanztyp  T (Instanztyp), beginnend mit dem Instanztyp der unmittelbar einschließenden Typdeklaration und fortsetzen mit dem Instanztyp jeder einschließenden Klasse oder Struktur Deklaration (sofern vorhanden):Otherwise, for each instance type T (The instance type), starting with the instance type of the immediately enclosing type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):

    • Wenn K 0 (null) ist und die Deklaration von T einen Typparameter mit dem Namen enthält  I , verweist der Simple_name auf diesen Typparameter.If K is zero and the declaration of T includes a type parameter with name I, then the simple_name refers to that type parameter.
    • Andernfalls, wenn eine Member-Suche (Member-Suche) von I in T mit K   Typargumenten eine Entsprechung erzeugt:Otherwise, if a member lookup (Member lookup) of I in T with K type arguments produces a match:
      • Wenn T der Instanztyp der unmittelbar einschließenden Klasse oder des Struktur Typs ist und die Suche eine oder mehrere Methoden identifiziert, ist das Ergebnis eine Methoden Gruppe mit einem zugeordneten Instanzausdruck von this .If T is the instance type of the immediately enclosing class or struct type and the lookup identifies one or more methods, the result is a method group with an associated instance expression of this. Wenn eine Typargument Liste angegeben wurde, wird Sie beim Aufrufen einer generischen Methode (Methodenaufrufe) verwendet.If a type argument list was specified, it is used in calling a generic method (Method invocations).
      • Andernfalls, wenn der T Instanztyp der unmittelbar einschließenden Klasse oder des Struktur Typs ist, wenn die Suche einen Instanzmember identifiziert und der Verweis innerhalb des Texts eines Instanzkonstruktors, einer Instanzmethode oder eines Instanzaccessors auftritt, ist das Ergebnis das gleiche wie ein Element Zugriff (Member Access) des Formulars this.I .Otherwise, if T is the instance type of the immediately enclosing class or struct type, if the lookup identifies an instance member, and if the reference occurs within the body of an instance constructor, an instance method, or an instance accessor, the result is the same as a member access (Member access) of the form this.I. Dies kann nur vorkommen, wenn K 0 (null) ist.This can only happen when K is zero.
      • Andernfalls ist das Ergebnis das gleiche wie ein Element Zugriff (Member Access) des Formulars T.I oder T.I<A1,...,Ak> .Otherwise, the result is the same as a member access (Member access) of the form T.I or T.I<A1,...,Ak>. In diesem Fall handelt es sich um einen Bindungs Zeit Fehler, damit der Simple_name auf einen Instanzmember verweist.In this case, it is a binding-time error for the simple_name to refer to an instance member.
  • Andernfalls  N werden die folgenden Schritte für jeden Namespace, beginnend mit dem Namespace, in dem der Simple_name auftritt, mit jedem einschließenden Namespace (sofern vorhanden) und mit dem globalen Namespace fortgesetzt, bis eine Entität gefunden wird:Otherwise, for each namespace N, starting with the namespace in which the simple_name occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:

    • Wenn K 0 (null) ist und I der Name eines Namespace in ist  N , dann gilt Folgendes:If K is zero and I is the name of a namespace in N, then:
      • Wenn der Speicherort, an dem der Simple_name auftritt, von einer Namespace Deklaration für eingeschlossen ist N und die Namespace Deklaration eine extern_alias_directive oder using_alias_directive enthält, die den Namen  I einem Namespace oder Typ zuordnet, ist die Simple_name mehrdeutig, und es tritt ein Kompilierungsfehler auf.If the location where the simple_name occurs is enclosed by a namespace declaration for N and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with a namespace or type, then the simple_name is ambiguous and a compile-time error occurs.
      • Andernfalls verweist der Simple_name auf den Namespace mit dem Namen I in N .Otherwise, the simple_name refers to the namespace named I in N.
    • Wenn andernfalls einen zugreif baren N Typ mit den Parametern "Name" und "Type" enthält  I K   , dann:Otherwise, if N contains an accessible type having name I and K type parameters, then:
      • Wenn K 0 (null) ist und die Position, an der die Simple_name auftritt, von einer Namespace Deklaration für eingeschlossen wird N und die Namespace Deklaration eine extern_alias_directive oder using_alias_directive enthält, die den Namen  I einem Namespace oder Typ zuordnet, ist die Simple_name mehrdeutig und ein Kompilierzeitfehler aufgetreten.If K is zero and the location where the simple_name occurs is enclosed by a namespace declaration for N and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with a namespace or type, then the simple_name is ambiguous and a compile-time error occurs.
      • Andernfalls verweist der namespace_or_type_name auf den Typ, der mit den angegebenen Typargumenten erstellt wurde.Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
    • Andernfalls ist der Speicherort, an dem der Simple_name auftritt, von einer Namespace Deklaration für Folgendes eingeschlossen  N :Otherwise, if the location where the simple_name occurs is enclosed by a namespace declaration for N:
      • Wenn K 0 (null) ist und die-Namespace Deklaration eine extern_alias_directive oder using_alias_directive enthält, die den Namen  I einem importierten Namespace oder Typ zuordnet, verweist der Simple_name auf diesen Namespace oder Typ.If K is zero and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with an imported namespace or type, then the simple_name refers to that namespace or type.
      • Wenn die Namespaces und Typdeklarationen, die von den using_namespace_directive s und using_static_directive s der Namespace Deklaration importiert werden, genau einen zugreif baren Typ oder einen statischen Member ohne Erweiterung haben, der über die Parameter "Name" und "Type" verfügt  I K   , verweist der Simple_name auf diesen Typ oder Member, der mit den angegebenen TypargumentenOtherwise, if the namespaces and type declarations imported by the using_namespace_directive s and using_static_directive s of the namespace declaration contain exactly one accessible type or non-extension static member having name I and K type parameters, then the simple_name refers to that type or member constructed with the given type arguments.
      • Wenn die Namespaces und Typen, die durch die using_namespace_directive s der Namespace Deklaration importiert werden, mehr als einen zugreif baren Typ oder einen statischen Member ohne Erweiterungsmethode haben, der über die Parameter "Name" und "Type" verfügt  I K   , ist die Simple_name mehrdeutig und ein Fehler.Otherwise, if the namespaces and types imported by the using_namespace_directive s of the namespace declaration contain more than one accessible type or non-extension-method static member having name I and K type parameters, then the simple_name is ambiguous and an error occurs.

    Beachten Sie, dass der gesamte Schritt genau mit dem entsprechenden Schritt bei der Verarbeitung eines namespace_or_type_name (Namespace-und Typnamen) identisch ist.Note that this entire step is exactly parallel to the corresponding step in the processing of a namespace_or_type_name (Namespace and type names).

  • Andernfalls ist der Simple_name nicht definiert, und es tritt ein Kompilierzeitfehler auf.Otherwise, the simple_name is undefined and a compile-time error occurs.

Ausdrücke in KlammernParenthesized expressions

Ein parenthesized_expression besteht aus einem Ausdruck , der in Klammern eingeschlossen ist.A parenthesized_expression consists of an expression enclosed in parentheses.

parenthesized_expression
    : '(' expression ')'
    ;

Eine parenthesized_expression wird ausgewertet, indem der Ausdruck innerhalb der Klammern ausgewertet wird.A parenthesized_expression is evaluated by evaluating the expression within the parentheses. Wenn der Ausdruck innerhalb der Klammern einen Namespace oder Typ angibt, tritt ein Kompilierzeitfehler auf.If the expression within the parentheses denotes a namespace or type, a compile-time error occurs. Andernfalls ist das Ergebnis der parenthesized_expression das Ergebnis der Auswertung des enthaltenen Ausdrucks.Otherwise, the result of the parenthesized_expression is the result of the evaluation of the contained expression.

MemberzugriffMember access

Eine member_access besteht aus einem primary_expression, einem predefined_type oder einem qualified_alias_member, gefolgt von einem " . "-Token, gefolgt von einem Bezeichner, optional gefolgt von einem type_argument_list.A member_access consists of a primary_expression, a predefined_type, or a qualified_alias_member, followed by a "." token, followed by an identifier, optionally followed by a type_argument_list.

member_access
    : primary_expression '.' identifier type_argument_list?
    | predefined_type '.' identifier type_argument_list?
    | qualified_alias_member '.' identifier
    ;

predefined_type
    : 'bool'   | 'byte'  | 'char'  | 'decimal' | 'double' | 'float' | 'int' | 'long'
    | 'object' | 'sbyte' | 'short' | 'string'  | 'uint'   | 'ulong' | 'ushort'
    ;

Die qualified_alias_member Produktion wird in Namespacealias-Qualifiziererndefiniert.The qualified_alias_member production is defined in Namespace alias qualifiers.

Ein member_access weist entweder das Formular E.I oder das Format auf E.I<A1, ..., Ak> , wobei E ein primärer Ausdruck ist, I ein einzelner Bezeichner ist und <A1, ..., Ak> ein optionaler type_argument_list ist.A member_access is either of the form E.I or of the form E.I<A1, ..., Ak>, where E is a primary-expression, I is a single identifier and <A1, ..., Ak> is an optional type_argument_list. Wenn keine type_argument_list angegeben ist, sollten K Sie den Wert 0 (null) angeben.When no type_argument_list is specified, consider K to be zero.

Eine member_access mit einer primary_expression vom Typ dynamic ist dynamisch gebunden (dynamische Bindung).A member_access with a primary_expression of type dynamic is dynamically bound (Dynamic binding). In diesem Fall klassifiziert der Compiler den Member Access als Eigenschaften Zugriff vom Typ dynamic .In this case the compiler classifies the member access as a property access of type dynamic. Die nachstehenden Regeln zum Bestimmen der Bedeutung der member_access werden dann zur Laufzeit angewendet und verwenden den Lauf Zeittyp anstelle des Kompilierzeit Typs der primary_expression.The rules below to determine the meaning of the member_access are then applied at run-time, using the run-time type instead of the compile-time type of the primary_expression. Wenn diese Lauf Zeit Klassifizierung zu einer Methoden Gruppe führt, muss der Element Zugriff die primary_expression eines invocation_expression sein.If this run-time classification leads to a method group, then the member access must be the primary_expression of an invocation_expression.

Die member_access wird wie folgt ausgewertet und klassifiziert:The member_access is evaluated and classified as follows:

  • Wenn K 0 (null) ist und E ein Namespace ist und E einen schsted Namespace mit dem Namen enthält  I , ist das Ergebnis dieser Namespace.If K is zero and E is a namespace and E contains a nested namespace with name I, then the result is that namespace.
  • Wenn E ein Namespace ist und E einen zugänglichen Typ  I mit den Parametern "Name" und "Type" enthält K   , ist das Ergebnis der Typ, der mit den angegebenen Typargumenten erstellt wurde.Otherwise, if E is a namespace and E contains an accessible type having name I and K type parameters, then the result is that type constructed with the given type arguments.
  • Wenn E ein predefined_type oder ein primary_expression als Typ klassifiziert ist, wenn E kein Typparameter ist, und wenn eine Member-Suche (Member-Suche) von I in E mit K   Typparametern eine Entsprechung erzeugt, E.I wird wie folgt ausgewertet und klassifiziert:If E is a predefined_type or a primary_expression classified as a type, if E is not a type parameter, and if a member lookup (Member lookup) of I in E with K type parameters produces a match, then E.I is evaluated and classified as follows:
    • Wenn I einen Typ identifiziert, ist das Ergebnis der Typ, der mit den angegebenen Typargumenten erstellt wurde.If I identifies a type, then the result is that type constructed with the given type arguments.
    • Wenn I eine oder mehrere Methoden identifiziert, ist das Ergebnis eine Methoden Gruppe ohne zugeordneten Instanzausdruck.If I identifies one or more methods, then the result is a method group with no associated instance expression. Wenn eine Typargument Liste angegeben wurde, wird Sie beim Aufrufen einer generischen Methode (Methodenaufrufe) verwendet.If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Wenn I eine static Eigenschaft identifiziert, ist das Ergebnis ein Eigenschaften Zugriff ohne zugeordneten Instanzausdruck.If I identifies a static property, then the result is a property access with no associated instance expression.
    • Wenn I ein static Feld angibt:If I identifies a static field:
      • Wenn das Feld den readonly Wert hat und der Verweis außerhalb des statischen Konstruktors der Klasse oder Struktur auftritt, in der das Feld deklariert ist, dann ist das Ergebnis ein Wert, nämlich der Wert des statischen Felds  I in  E .If the field is readonly and the reference occurs outside the static constructor of the class or struct in which the field is declared, then the result is a value, namely the value of the static field I in E.
      • Andernfalls ist das Ergebnis eine Variable, nämlich das statische Feld  I in  E .Otherwise, the result is a variable, namely the static field I in E.
    • Wenn I ein- static Ereignis identifiziert:If I identifies a static event:
      • Wenn der Verweis innerhalb der Klasse oder Struktur auftritt, in der das Ereignis deklariert ist, und das Ereignis ohne event_accessor_declarations (Ereignisse) deklariert wurde, E.I wird genau so verarbeitet, als wäre es I ein statisches Feld.If the reference occurs within the class or struct in which the event is declared, and the event was declared without event_accessor_declarations (Events), then E.I is processed exactly as if I were a static field.
      • Andernfalls ist das Ergebnis ein Ereignis Zugriff ohne zugeordneten Instanzausdruck.Otherwise, the result is an event access with no associated instance expression.
    • Wenn I eine Konstante identifiziert, ist das Ergebnis ein Wert, nämlich der Wert dieser Konstante.If I identifies a constant, then the result is a value, namely the value of that constant.
    • Wenn I einen Enumerationsmember identifiziert, ist das Ergebnis ein Wert, nämlich der Wert dieses Enumerationsmembers.If I identifies an enumeration member, then the result is a value, namely the value of that enumeration member.
    • Andernfalls E.I ist ein ungültiger Member-Verweis, und ein Kompilierzeitfehler tritt auf.Otherwise, E.I is an invalid member reference, and a compile-time error occurs.
  • Wenn E ein Eigenschaften Zugriff, Indexer-Zugriff, Variable oder Wert ist, der Typ ist  T , und eine Member-Suche (Member-Suche) von I in T mit K   Typargumenten eine Entsprechung erzeugt, E.I wird wie folgt ausgewertet und klassifiziert:If E is a property access, indexer access, variable, or value, the type of which is T, and a member lookup (Member lookup) of I in T with K type arguments produces a match, then E.I is evaluated and classified as follows:
    • Zuerst wird E der Wert der Eigenschaft oder des Indexerzugriffs abgerufen (Werte von Ausdrücken) und E als Wert neu klassifiziert, wenn ein Eigenschafts-oder Indexer-Zugriff ist.First, if E is a property or indexer access, then the value of the property or indexer access is obtained (Values of expressions) and E is reclassified as a value.
    • Wenn I eine oder mehrere Methoden identifiziert, ist das Ergebnis eine Methoden Gruppe mit einem zugeordneten Instanzausdruck von E .If I identifies one or more methods, then the result is a method group with an associated instance expression of E. Wenn eine Typargument Liste angegeben wurde, wird Sie beim Aufrufen einer generischen Methode (Methodenaufrufe) verwendet.If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Wenn I eine Instanzeigenschaft identifiziert,If I identifies an instance property,
      • Wenn E ist this , I eine automatisch implementierte Eigenschaft (automatisch implementierte Eigenschaften) ohne Setter identifiziert, und der Verweis innerhalb eines Instanzkonstruktors für einen Klassen-oder Strukturtyp ist T , dann ist das Ergebnis eine Variable, d. h. das verborgene dahinter liegende Feld für die Auto-Eigenschaft, die I in der Instanz von angegeben ist, die T von angegeben wird this .If E is this, I identifies an automatically implemented property (Automatically implemented properties) without a setter, and the reference occurs within an instance constructor for a class or struct type T, then the result is a variable, namely the hidden backing field for the auto-property given by I in the instance of T given by this.
      • Andernfalls ist das Ergebnis ein Eigenschaften Zugriff mit einem zugeordneten Instanzausdruck von  E .Otherwise, the result is a property access with an associated instance expression of E.
    • Wenn T ein class_type ist und I ein Instanzfeld dieses class_type angibt:If T is a class_type and I identifies an instance field of that class_type:
      • Wenn der Wert von E ist null , wird eine ausgelöst System.NullReferenceException .If the value of E is null, then a System.NullReferenceException is thrown.
      • Andernfalls readonly ist das Ergebnis ein Wert, d. h. der Wert des Felds in dem Objekt, auf das verwiesen wird, wenn das Feld den Wert hat und der Verweis außerhalb eines Instanzkonstruktors der Klasse auftritt, in der das Feld deklariert ist  I  E .Otherwise, if the field is readonly and the reference occurs outside an instance constructor of the class in which the field is declared, then the result is a value, namely the value of the field I in the object referenced by E.
      • Andernfalls ist das Ergebnis eine Variable, nämlich das Feld  I in dem Objekt, auf das von verwiesen wird  E .Otherwise, the result is a variable, namely the field I in the object referenced by E.
    • Wenn T ein struct_type ist und I ein Instanzfeld dieses struct_type angibt:If T is a struct_type and I identifies an instance field of that struct_type:
      • Wenn E ein Wert ist oder wenn das Feld ist readonly und der Verweis außerhalb eines Instanzkonstruktors der Struktur auftritt, in der das Feld deklariert ist, dann ist das Ergebnis ein Wert, d. h. der Wert des Felds  I in der Struktur Instanz, die von angegeben wird  E .If E is a value, or if the field is readonly and the reference occurs outside an instance constructor of the struct in which the field is declared, then the result is a value, namely the value of the field I in the struct instance given by E.
      • Andernfalls ist das Ergebnis eine Variable, nämlich das Feld  I in der Struktur Instanz, das von angegeben wird  E .Otherwise, the result is a variable, namely the field I in the struct instance given by E.
    • Wenn I ein Instanzereignis angibt:If I identifies an instance event:
      • Wenn der Verweis innerhalb der Klasse oder Struktur auftritt, in der das Ereignis deklariert ist, und das Ereignis ohne event_accessor_declarations (Ereignisse) deklariert wurde, und der Verweis nicht als linke Seite eines or- += Operators auftritt -= , E.I wird genau so verarbeitet, als wäre I ein Instanzfeld.If the reference occurs within the class or struct in which the event is declared, and the event was declared without event_accessor_declarations (Events), and the reference does not occur as the left-hand side of a += or -= operator, then E.I is processed exactly as if I was an instance field.
      • Andernfalls ist das Ergebnis ein Ereignis Zugriff mit einem zugeordneten Instanzausdruck von  E .Otherwise, the result is an event access with an associated instance expression of E.
  • Andernfalls wird versucht, E.I als Erweiterungs Methodenaufruf (Erweiterungs Methodenaufrufe) zu verarbeiten.Otherwise, an attempt is made to process E.I as an extension method invocation (Extension method invocations). Wenn dies nicht möglich E.I ist, ist ein ungültiger Element Verweis, und ein Bindungs Fehler tritt auf.If this fails, E.I is an invalid member reference, and a binding-time error occurs.

Identische einfache Namen und TypnamenIdentical simple names and type names

Wenn ein Element Zugriff auf das Formular E.I ist, wenn E ein einzelner Bezeichner ist und die Bedeutung von E als Simple_name (einfache Namen) eine Konstante, ein Feld, eine Eigenschaft, eine lokale Variable oder ein Parameter mit demselben Typ wie die Bedeutung von E als TYPE_NAME (Namespace-und Typnamen) ist, sind beide möglichen Bedeutungen von E zulässig.In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple_name (Simple names) is a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type_name (Namespace and type names), then both possible meanings of E are permitted. Die beiden möglichen Bedeutungen von E.I sind nie mehrdeutig, da I E in beiden Fällen notwendigerweise ein Member des-Typs sein muss.The two possible meanings of E.I are never ambiguous, since I must necessarily be a member of the type E in both cases. Anders ausgedrückt: die Regel gestattet einfach den Zugriff auf die statischen Member und die schsted Typen, E bei denen andernfalls ein Kompilierzeitfehler aufgetreten ist.In other words, the rule simply permits access to the static members and nested types of E where a compile-time error would otherwise have occurred. Beispiel:For example:

struct Color
{
    public static readonly Color White = new Color(...);
    public static readonly Color Black = new Color(...);

    public Color Complement() {...}
}

class A
{
    public Color Color;                // Field Color of type Color

    void F() {
        Color = Color.Black;           // References Color.Black static member
        Color = Color.Complement();    // Invokes Complement() on Color field
    }

    static void G() {
        Color c = Color.White;         // References Color.White static member
    }
}

Grammatik MehrdeutigkeitenGrammar ambiguities

Die Produktion für Simple_name (einfache Namen) und member_access (Member Access) kann zu Mehrdeutigkeiten in der Grammatik für Ausdrücke führen.The productions for simple_name (Simple names) and member_access (Member access) can give rise to ambiguities in the grammar for expressions. Beispielsweise ist die-Anweisung:For example, the statement:

F(G<A,B>(7));

kann als ein F -Befehl mit zwei Argumenten (und) interpretiert werden G < A B > (7) .could be interpreted as a call to F with two arguments, G < A and B > (7). Alternativ könnte Sie auch als ein-Rückruf F mit einem Argument interpretiert werden, bei dem es sich um einen aufgerufenen Vorgang einer generischen Methode  G mit zwei Typargumenten und einem regulären Argument handelt.Alternatively, it could be interpreted as a call to F with one argument, which is a call to a generic method G with two type arguments and one regular argument.

Wenn eine Sequenz von Token (im Kontext) als Simple_name (einfache Namen), member_access (Member Access) oder pointer_member_access (Zeiger Element Zugriff) mit einer type_argument_list (Typargumente) analysiert werden kann, wird das Token, das unmittelbar auf das schließende Token folgt, > untersucht.If a sequence of tokens can be parsed (in context) as a simple_name (Simple names), member_access (Member access), or pointer_member_access (Pointer member access) ending with a type_argument_list (Type arguments), the token immediately following the closing > token is examined. Wenn eine vonIf it is one of

(  )  ]  }  :  ;  ,  .  ?  ==  !=  |  ^

Anschließend wird der type_argument_list als Teil der Simple_name, member_access oder pointer_member_access aufbewahrt, und jede andere mögliche Analyse der Sequenz von Token wird verworfen.then the type_argument_list is retained as part of the simple_name, member_access or pointer_member_access and any other possible parse of the sequence of tokens is discarded. Andernfalls wird der type_argument_list nicht als Teil der Simple_name, member_access oder pointer_member_access betrachtet, auch wenn es keine andere Möglichkeit gibt, die Sequenz von Token zu analysieren.Otherwise, the type_argument_list is not considered to be part of the simple_name, member_access or pointer_member_access, even if there is no other possible parse of the sequence of tokens. Beachten Sie, dass diese Regeln beim Durchlaufen einer type_argument_list in einer namespace_or_type_name (Namespace-und Typnamen) nicht angewendet werden.Note that these rules are not applied when parsing a type_argument_list in a namespace_or_type_name (Namespace and type names). Die AnweisungThe statement

F(G<A,B>(7));

wird gemäß dieser Regel als ein-Rückruf F mit einem Argument interpretiert, bei dem es sich um einen Aufrufe einer generischen Methode G mit zwei Typargumenten und einem regulären Argument handelt.will, according to this rule, be interpreted as a call to F with one argument, which is a call to a generic method G with two type arguments and one regular argument. Die AnweisungenThe statements

F(G < A, B > 7);
F(G < A, B >> 7);

wird jeweils als ein-Rückruf F mit zwei Argumenten interpretiert.will each be interpreted as a call to F with two arguments. Die AnweisungThe statement

x = F < A > +y;

wird als ein kleiner-als-Operator, größer als-Operator und Unärer Plus-Operator interpretiert, als ob die-Anweisung geschrieben worden wäre x = (F < A) > (+y) , anstatt als Simple_name mit einem type_argument_list gefolgt von einem binären Plus-Operator.will be interpreted as a less than operator, greater than operator, and unary plus operator, as if the statement had been written x = (F < A) > (+y), instead of as a simple_name with a type_argument_list followed by a binary plus operator. In der-AnweisungIn the statement

x = y is C<T> + z;

die Token C<T> werden als namespace_or_type_name mit einem type_argument_list interpretiert.the tokens C<T> are interpreted as a namespace_or_type_name with a type_argument_list.

AufrufausdrückeInvocation expressions

Ein invocation_expression wird verwendet, um eine Methode aufzurufen.An invocation_expression is used to invoke a method.

invocation_expression
    : primary_expression '(' argument_list? ')'
    ;

Ein- invocation_expression ist dynamisch gebunden (dynamische Bindung), wenn mindestens einer der folgenden Punkte enthält:An invocation_expression is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Der primary_expression weist den Kompilier Zeittyp auf dynamic .The primary_expression has compile-time type dynamic.
  • Mindestens ein Argument der optionalen argument_list hat einen Kompilier Zeittyp, dynamic und die primary_expression weist keinen Delegattyp auf.At least one argument of the optional argument_list has compile-time type dynamic and the primary_expression does not have a delegate type.

In diesem Fall klassifiziert der Compiler die invocation_expression als Wert des Typs dynamic .In this case the compiler classifies the invocation_expression as a value of type dynamic. Die nachstehenden Regeln zum Bestimmen der Bedeutung der invocation_expression werden dann zur Laufzeit angewendet. dabei wird der Lauf Zeittyp anstelle des Kompilier Zeittyps der primary_expression und Argumente verwendet, die den Kompilier Zeittyp aufweisen dynamic .The rules below to determine the meaning of the invocation_expression are then applied at run-time, using the run-time type instead of the compile-time type of those of the primary_expression and arguments which have the compile-time type dynamic. Wenn das primary_expression keinen Kompilier Zeittyp hat dynamic , wird der Methodenaufruf einer begrenzten Kompilierungszeit Überprüfung unterzogen, wie in der Kompilierzeit Überprüfung der dynamischen Überladungs Auflösungbeschrieben.If the primary_expression does not have compile-time type dynamic, then the method invocation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

Der primary_expression eines invocation_expression muss eine Methoden Gruppe oder ein Wert eines delegate_type sein.The primary_expression of an invocation_expression must be a method group or a value of a delegate_type. Wenn die primary_expression eine Methoden Gruppe ist, ist die invocation_expression ein Methodenaufruf (Methodenaufrufe).If the primary_expression is a method group, the invocation_expression is a method invocation (Method invocations). Wenn die primary_expression ein Wert eines delegate_type ist, ist der invocation_expression ein Delegataufruf (Delegataufrufe).If the primary_expression is a value of a delegate_type, the invocation_expression is a delegate invocation (Delegate invocations). Wenn die primary_expression weder eine Methoden Gruppe noch der Wert eines delegate_type ist, tritt ein Bindungs Fehler auf.If the primary_expression is neither a method group nor a value of a delegate_type, a binding-time error occurs.

Die optionalen argument_list (Argumentlisten) stellen Werte oder Variablen Verweise für die Parameter der Methode bereit.The optional argument_list (Argument lists) provides values or variable references for the parameters of the method.

Das Ergebnis der Auswertung eines invocation_expression wird wie folgt klassifiziert:The result of evaluating an invocation_expression is classified as follows:

  • Wenn die invocation_expression eine Methode oder einen Delegaten aufruft, die zurückgibt void , ist das Ergebnis "Nothing".If the invocation_expression invokes a method or delegate that returns void, the result is nothing. Ein Ausdruck, der als "Nothing" klassifiziert wird, ist nur im Kontext einer statement_expression (Ausdrucks Anweisungen) oder als Text eines lambda_expression (Anonyme Funktions Ausdrücke) zulässig.An expression that is classified as nothing is permitted only in the context of a statement_expression (Expression statements) or as the body of a lambda_expression (Anonymous function expressions). Andernfalls tritt ein Bindungs Zeitfehler auf.Otherwise a binding-time error occurs.
  • Andernfalls ist das Ergebnis ein Wert des Typs, der von der-Methode oder dem-Delegaten zurückgegeben wird.Otherwise, the result is a value of the type returned by the method or delegate.

MethodenaufrufeMethod invocations

Bei einem Methodenaufruf muss die primary_expression der invocation_expression eine Methoden Gruppe sein.For a method invocation, the primary_expression of the invocation_expression must be a method group. Die Methoden Gruppe identifiziert die eine Methode, die aufgerufen werden soll, oder den Satz überladener Methoden, von denen eine bestimmte aufzurufende Methode ausgewählt werden soll.The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke. Im letzteren Fall basiert die Bestimmung der aufzurufenden Methode auf dem Kontext, der von den Typen der Argumente im argument_list bereitgestellt wird.In the latter case, determination of the specific method to invoke is based on the context provided by the types of the arguments in the argument_list.

Die Bindungs Zeit Verarbeitung eines Methoden M(A) aufruens im Formular, wobei M eine Methoden Gruppe (möglicherweise ein type_argument_list) und A ein optionaler argument_list ist, besteht aus den folgenden Schritten:The binding-time processing of a method invocation of the form M(A), where M is a method group (possibly including a type_argument_list), and A is an optional argument_list, consists of the following steps:

  • Der Satz von Kandidaten Methoden für den Methodenaufruf wird erstellt.The set of candidate methods for the method invocation is constructed. Für jede Methode, F die der Methoden Gruppe zugeordnet ist M :For each method F associated with the method group M:
    • Wenn F nicht generisch ist, F ist ein Kandidat, wenn:If F is non-generic, F is a candidate when:
    • Wenn F generisch ist und M keine Typargument Liste aufweist, F ist ein Kandidat für Folgendes:If F is generic and M has no type argument list, F is a candidate when:
      • Der Typrückschluss (Typrückschluss) ist erfolgreich, wobei eine Liste der Typargumente für den-Befehl abgeleitet wird.Type inference (Type inference) succeeds, inferring a list of type arguments for the call, and
      • Nachdem die abzurufenden Typargumente die entsprechenden Methodentypparameter ersetzt haben, erfüllen alle konstruierten Typen in der Parameterliste von F ihre Einschränkungen (die dieEinschränkungenerfüllen), und die Parameterliste von F ist in Bezug auf A (anwendbares Funktionsmember) anwendbar.Once the inferred type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (Satisfying constraints), and the parameter list of F is applicable with respect to A (Applicable function member).
    • Wenn F generisch ist und M eine Typargument Liste enthält, F ist ein Kandidat, wenn Folgendes gilt:If F is generic and M includes a type argument list, F is a candidate when:
      • F verfügt über die gleiche Anzahl von Methodentypparametern, die in der Typargument Liste angegeben wurden, undF has the same number of method type parameters as were supplied in the type argument list, and
      • Nachdem die Typargumente die entsprechenden Methodentypparameter ersetzt haben, erfüllen alle konstruierten Typen in der Parameterliste von F ihre Einschränkungen (die dieEinschränkungenerfüllen), und die Parameterliste von F ist in Bezug auf A (anwendbares Funktionsmember) anwendbar.Once the type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (Satisfying constraints), and the parameter list of F is applicable with respect to A (Applicable function member).
  • Der Satz von Kandidaten Methoden wird so reduziert, dass er nur Methoden der am weitesten abgeleiteten Typen enthält: für jede Methode C.F in der Menge, wobei C der Typ ist, in dem die Methode F deklariert ist, werden alle Methoden, die in einem Basistyp von deklariert C sind, aus dem Satz entfernt.The set of candidate methods is reduced to contain only methods from the most derived types: For each method C.F in the set, where C is the type in which the method F is declared, all methods declared in a base type of C are removed from the set. Wenn außerdem C ein anderer Klassentyp als ist object , werden alle in einem Schnittstellentyp deklarierten Methoden aus dem Satz entfernt.Furthermore, if C is a class type other than object, all methods declared in an interface type are removed from the set. (Diese letztere Regel hat nur Auswirkungen, wenn die Methoden Gruppe das Ergebnis einer Member-Suche nach einem Typparameter ist, der eine effektive Basisklasse als Object und eine nicht leere effektive Schnittstellen Menge aufweist.)(This latter rule only has affect when the method group was the result of a member lookup on a type parameter having an effective base class other than object and a non-empty effective interface set.)
  • Wenn der resultierende Satz von Kandidaten Methoden leer ist, wird die weitere Verarbeitung der folgenden Schritte abgebrochen, und stattdessen wird versucht, den Aufruf als Erweiterungs Methodenaufruf (Erweiterungs Methodenaufrufe) zu verarbeiten.If the resulting set of candidate methods is empty, then further processing along the following steps are abandoned, and instead an attempt is made to process the invocation as an extension method invocation (Extension method invocations). Wenn dies fehlschlägt, gibt es keine anwendbaren Methoden, und ein Bindungs Fehler tritt auf.If this fails, then no applicable methods exist, and a binding-time error occurs.
  • Die beste Methode des Satzes von Kandidaten Methoden wird mithilfe der Regeln zur Überladungs Auflösung der Überladungs Auflösungidentifiziert.The best method of the set of candidate methods is identified using the overload resolution rules of Overload resolution. Wenn eine einzige optimale Methode nicht identifiziert werden kann, ist der Methodenaufruf mehrdeutig, und es tritt ein Fehler bei der Bindung auf.If a single best method cannot be identified, the method invocation is ambiguous, and a binding-time error occurs. Beim Durchführen der Überladungs Auflösung werden die Parameter einer generischen Methode berücksichtigt, nachdem die Typargumente (bereitgestellt oder abgeleitet) für die entsprechenden Methodentyp Parameter ersetzt wurden.When performing overload resolution, the parameters of a generic method are considered after substituting the type arguments (supplied or inferred) for the corresponding method type parameters.
  • Die endgültige Überprüfung der ausgewählten optimalen Methode wird ausgeführt:Final validation of the chosen best method is performed:
    • Die-Methode wird im Kontext der-Methoden Gruppe überprüft: Wenn es sich bei der besten Methode um eine statische Methode handelt, muss die Methoden Gruppe aus einer Simple_name oder einer member_access durch einen Typ resultieren.The method is validated in the context of the method group: If the best method is a static method, the method group must have resulted from a simple_name or a member_access through a type. Wenn die beste Methode eine Instanzmethode ist, muss die Methoden Gruppe durch eine Simple_name, eine member_access durch eine Variable oder einen Wert oder eine base_access resultieren.If the best method is an instance method, the method group must have resulted from a simple_name, a member_access through a variable or value, or a base_access. Wenn keine dieser Anforderungen erfüllt ist, tritt ein Fehler bei der Bindung auf.If neither of these requirements is true, a binding-time error occurs.
    • Wenn es sich bei der besten Methode um eine generische Methode handelt, werden die Typargumente (bereitgestellt oder abgeleitet) mit den Einschränkungen (die sich durch dieErfüllung der Einschränkungenin der generischen Methode) überprüfenIf the best method is a generic method, the type arguments (supplied or inferred) are checked against the constraints (Satisfying constraints) declared on the generic method. Wenn ein Typargument die entsprechenden Einschränkungen für den Typparameter nicht erfüllt, tritt ein Bindungs Zeitfehler auf.If any type argument does not satisfy the corresponding constraint(s) on the type parameter, a binding-time error occurs.

Nachdem eine Methode mithilfe der obigen Schritte zur Bindungs Zeit ausgewählt und überprüft wurde, wird der tatsächliche Lauf Zeit Aufruf gemäß den Regeln für den Funktionselement Aufruf verarbeitet, der unter Kompilierzeit Überprüfung der dynamischen Überladungs Auflösungbeschrieben wird.Once a method has been selected and validated at binding-time by the above steps, the actual run-time invocation is processed according to the rules of function member invocation described in Compile-time checking of dynamic overload resolution.

Die intuitiver Auswirkung der oben beschriebenen Auflösungs Regeln lautet wie folgt: um die von einem Methodenaufruf aufgerufene Methode zu suchen, beginnen Sie mit dem Typ, der durch den Methodenaufruf angegeben wird, und setzen Sie die Vererbungs Kette fort, bis mindestens eine anwendbare, barrierefreie, nicht über schreibende Methoden Deklaration gefunden wurde.The intuitive effect of the resolution rules described above is as follows: To locate the particular method invoked by a method invocation, start with the type indicated by the method invocation and proceed up the inheritance chain until at least one applicable, accessible, non-override method declaration is found. Führen Sie dann den Typrückschluss und die Überladungs Auflösung für den Satz der anwendbaren, zugänglichen, nicht überschreibenden Methoden aus, die in diesem Typ deklariert sind, und rufen Sie die Methode aufThen perform type inference and overload resolution on the set of applicable, accessible, non-override methods declared in that type and invoke the method thus selected. Wenn keine Methode gefunden wurde, versuchen Sie stattdessen, den Aufruf als Erweiterungs Methodenaufruf zu verarbeiten.If no method was found, try instead to process the invocation as an extension method invocation.

Erweiterungs MethodenaufrufeExtension method invocations

In einem Methodenaufruf (Aufrufe für geboxte Instanzen) eines der FormulareIn a method invocation (Invocations on boxed instances) of one of the forms

expr . identifier ( )

expr . identifier ( args )

expr . identifier < typeargs > ( )

expr . identifier < typeargs > ( args )

Wenn bei der normalen Verarbeitung des aufzurufenden-aufzurufenden keine anwendbaren Methoden gefunden werden, wird versucht, das Konstrukt als Erweiterungs Methodenaufruf zu verarbeiten.if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. Wenn expr oder eines der args den Kompilier Zeittyp aufweist dynamic , werden keine Erweiterungs Methoden angewendet.If expr or any of the args has compile-time type dynamic, extension methods will not apply.

Ziel ist es, die beste TYPE_NAME zu finden C , damit der entsprechende Aufruf der statischen Methode stattfinden kann:The objective is to find the best type_name C, so that the corresponding static method invocation can take place:

C . identifier ( expr )

C . identifier ( expr , args )

C . identifier < typeargs > ( expr )

C . identifier < typeargs > ( expr , args )

Eine Erweiterungsmethode Ci.Mj ist berechtigt , wenn Folgendes gilt:An extension method Ci.Mj is eligible if:

  • Ci ist eine nicht generische, nicht-Klassen-Klasse.Ci is a non-generic, non-nested class
  • Der Name von Mj ist ein Bezeichner .The name of Mj is identifier
  • Mj ist verfügbar und anwendbar, wenn Sie auf die Argumente als statische Methode angewendet wird, wie oben gezeigt.Mj is accessible and applicable when applied to the arguments as a static method as shown above
  • Eine implizite Identitäts-, Verweis-oder Boxingkonvertierung ist von expr zum Typ des ersten Parameters von vorhanden Mj .An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter of Mj.

Die Suche nach C verläuft wie folgt:The search for C proceeds as follows:

  • Beginnend mit der nächstgelegenen, einschließenden Namespace Deklaration, der Fortsetzung der einschließenden Namespace Deklaration und dem Ende der enthaltenden Kompilierungseinheit werden nachfolgende Versuche unternommen, um einen Kandidaten Satz von Erweiterungs Methoden zu finden:Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods:
    • Wenn der angegebene Namespace oder die Kompilierungseinheit direkt nicht generische Typdeklarationen Ci mit berechtigten Erweiterungs Methoden enthält Mj , ist der Satz dieser Erweiterungs Methoden der Kandidaten Satz.If the given namespace or compilation unit directly contains non-generic type declarations Ci with eligible extension methods Mj, then the set of those extension methods is the candidate set.
    • Wenn Typen, die Ci von using_static_declarations importiert und direkt in Namespaces deklariert werden, die von using_namespace_directive s in den angegebenen Namespace oder in der Kompilierungseinheit importiert wurden, die geeigneten Erweiterungs Methoden direkt enthalten Mj , ist der Satz dieser Erweiterungs Methoden der Kandidaten Satz.If types Ci imported by using_static_declarations and directly declared in namespaces imported by using_namespace_directive s in the given namespace or compilation unit directly contain eligible extension methods Mj, then the set of those extension methods is the candidate set.
  • Wenn kein Kandidaten Satz in einer einschließenden Namespace Deklaration oder Kompilierungseinheit gefunden wird, tritt ein Kompilierzeitfehler auf.If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
  • Andernfalls wird die Überladungs Auflösung auf den Kandidaten Satz angewendet, wie in (Überladungs Auflösung) beschrieben.Otherwise, overload resolution is applied to the candidate set as described in (Overload resolution). Wenn keine einzige optimale Methode gefunden wird, tritt ein Kompilierzeitfehler auf.If no single best method is found, a compile-time error occurs.
  • C der Typ, in dem die beste Methode als Erweiterungsmethode deklariert wird.C is the type within which the best method is declared as an extension method.

CWenn als Ziel verwendet wird, wird der Methodenaufruf als statischer Methodenaufruf verarbeitet (Kompilierzeit Überprüfung der dynamischen Überladungs Auflösung).Using C as a target, the method call is then processed as a static method invocation (Compile-time checking of dynamic overload resolution).

Die vorstehenden Regeln bedeuten, dass Instanzmethoden Vorrang vor Erweiterungs Methoden haben, dass die in inneren Namespace Deklarationen verfügbaren Erweiterungs Methoden Vorrang vor Erweiterungs Methoden haben, die in äußeren Namespace Deklarationen verfügbar sind, und dass Erweiterungs Methoden, die direkt in einem Namespace deklariert werden, Vorrang vor Erweiterungs Methoden haben, die mit einer using-namespace Direktive in denselben NamespaceThe preceding rules mean that instance methods take precedence over extension methods, that extension methods available in inner namespace declarations take precedence over extension methods available in outer namespace declarations, and that extension methods declared directly in a namespace take precedence over extension methods imported into that same namespace with a using namespace directive. Beispiel:For example:

public static class E
{
    public static void F(this object obj, int i) { }

    public static void F(this object obj, string s) { }
}

class A { }

class B
{
    public void F(int i) { }
}

class C
{
    public void F(object obj) { }
}

class X
{
    static void Test(A a, B b, C c) {
        a.F(1);              // E.F(object, int)
        a.F("hello");        // E.F(object, string)

        b.F(1);              // B.F(int)
        b.F("hello");        // E.F(object, string)

        c.F(1);              // C.F(object)
        c.F("hello");        // C.F(object)
    }
}

In diesem Beispiel hat die B -Methode Vorrang vor der ersten Erweiterungsmethode, und C die-Methode hat Vorrang vor beiden Erweiterungs Methoden.In the example, B's method takes precedence over the first extension method, and C's method takes precedence over both extension methods.

public static class C
{
    public static void F(this int i) { Console.WriteLine("C.F({0})", i); }
    public static void G(this int i) { Console.WriteLine("C.G({0})", i); }
    public static void H(this int i) { Console.WriteLine("C.H({0})", i); }
}

namespace N1
{
    public static class D
    {
        public static void F(this int i) { Console.WriteLine("D.F({0})", i); }
        public static void G(this int i) { Console.WriteLine("D.G({0})", i); }
    }
}

namespace N2
{
    using N1;

    public static class E
    {
        public static void F(this int i) { Console.WriteLine("E.F({0})", i); }
    }

    class Test
    {
        static void Main(string[] args)
        {
            1.F();
            2.G();
            3.H();
        }
    }
}

Die Ausgabe dieses Beispiels lautet wie folgt:The output of this example is:

E.F(1)
D.G(2)
C.H(3)

D.G``C.Ghat Vorrang vor und hat Vorrang vor E.F D.F und C.F .D.G takes precedence over C.G, and E.F takes precedence over both D.F and C.F.

DelegataufrufeDelegate invocations

Bei einem Delegataufruf muss die primary_expression der invocation_expression ein Wert eines delegate_type sein.For a delegate invocation, the primary_expression of the invocation_expression must be a value of a delegate_type. Außerdem muss der delegate_type in Bezug auf den argument_list der invocation_expression anwendbar sein, wenn der delegate_type ein Funktionsmember mit derselben Parameterliste wie der delegate_type ist.Furthermore, considering the delegate_type to be a function member with the same parameter list as the delegate_type, the delegate_type must be applicable (Applicable function member) with respect to the argument_list of the invocation_expression.

Die Lauf Zeit Verarbeitung eines delegataufruens im Formular D(A) , wobei D eine primary_expression eines delegate_type und A ein optionaler argument_list ist, besteht aus den folgenden Schritten:The run-time processing of a delegate invocation of the form D(A), where D is a primary_expression of a delegate_type and A is an optional argument_list, consists of the following steps:

  • D wird ausgewertet.D is evaluated. Wenn diese Auswertung eine Ausnahme verursacht, werden keine weiteren Schritte ausgeführt.If this evaluation causes an exception, no further steps are executed.
  • Der Wert von D wird als gültig geprüft.The value of D is checked to be valid. Wenn der Wert von D ist null , wird eine ausgelöst, System.NullReferenceException und es werden keine weiteren Schritte ausgeführt.If the value of D is null, a System.NullReferenceException is thrown and no further steps are executed.
  • Andernfalls D ist ein Verweis auf eine Delegatinstanz.Otherwise, D is a reference to a delegate instance. Funktionsmember-Aufrufe (Kompilierungszeit Überprüfung der dynamischen Überladungs Auflösung) werden für jede der Aufruf baren Entitäten in der Aufruf Liste des Delegaten ausgeführt.Function member invocations (Compile-time checking of dynamic overload resolution) are performed on each of the callable entities in the invocation list of the delegate. Bei Aufruf baren Entitäten, die aus einer Instanz-und Instanzmethode bestehen, ist die Instanz für den Aufruf die Instanz, die in der Aufruf baren Entität enthalten ist.For callable entities consisting of an instance and instance method, the instance for the invocation is the instance contained in the callable entity.

ElementzugriffElement access

Eine element_access besteht aus einem primary_no_array_creation_expression, gefolgt von einem " [ "-Token, gefolgt von einem argument_list, gefolgt von einem " ] "-Token.An element_access consists of a primary_no_array_creation_expression, followed by a "[" token, followed by an argument_list, followed by a "]" token. Der argument_list besteht aus mindestens einem Argument s, getrennt durch Kommas.The argument_list consists of one or more argument s, separated by commas.

element_access
    : primary_no_array_creation_expression '[' expression_list ']'
    ;

Der argument_list eines element_access darf keine- ref oder-Argumente enthalten out .The argument_list of an element_access is not allowed to contain ref or out arguments.

Ein- element_access ist dynamisch gebunden (dynamische Bindung), wenn mindestens einer der folgenden Punkte enthält:An element_access is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Der primary_no_array_creation_expression weist den Kompilier Zeittyp auf dynamic .The primary_no_array_creation_expression has compile-time type dynamic.
  • Mindestens ein Ausdruck des argument_list hat einen Kompilier Zeittyp, dynamic und die primary_no_array_creation_expression weist keinen Arraytyp auf.At least one expression of the argument_list has compile-time type dynamic and the primary_no_array_creation_expression does not have an array type.

In diesem Fall klassifiziert der Compiler die element_access als Wert des Typs dynamic .In this case the compiler classifies the element_access as a value of type dynamic. Die nachstehenden Regeln zum Bestimmen der Bedeutung der element_access werden dann zur Laufzeit angewendet. dabei wird der Lauf Zeittyp anstelle des Kompilier Zeittyps der primary_no_array_creation_expression und argument_list Ausdrücke verwendet, die den Kompilier Zeittyp aufweisen dynamic .The rules below to determine the meaning of the element_access are then applied at run-time, using the run-time type instead of the compile-time type of those of the primary_no_array_creation_expression and argument_list expressions which have the compile-time type dynamic. Wenn das primary_no_array_creation_expression keinen Kompilier Zeittyp hat dynamic , wird der Zugriff auf die Kompilierzeit durch den Element Zugriff eingeschränkt, wie in der Kompilierzeit Überprüfung der dynamischen Überladungs Auflösungbeschrieben.If the primary_no_array_creation_expression does not have compile-time type dynamic, then the element access undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

Wenn die primary_no_array_creation_expression eines element_access ein Wert eines array_type ist, ist der element_access ein Array Zugriff (Array Zugriff).If the primary_no_array_creation_expression of an element_access is a value of an array_type, the element_access is an array access (Array access). Andernfalls muss es sich bei der primary_no_array_creation_expression um eine Variable oder einen Wert einer Klasse, Struktur oder eines Schnittstellen Typs handeln, die mindestens ein Indexer-Element aufweist. in diesem Fall ist der element_access ein Indexer-Zugriff (Indexer-Zugriff).Otherwise, the primary_no_array_creation_expression must be a variable or value of a class, struct, or interface type that has one or more indexer members, in which case the element_access is an indexer access (Indexer access).

ArrayzugriffArray access

Bei einem Array Zugriff muss die primary_no_array_creation_expression der element_access ein Wert eines array_type sein.For an array access, the primary_no_array_creation_expression of the element_access must be a value of an array_type. Außerdem darf die argument_list eines Array Zugriffs keine benannten Argumente enthalten. Die Anzahl der Ausdrücke in der argument_list muss mit dem Rang des array_type identisch sein, und jeder Ausdruck muss den Typ int , uint ,, oder aufweisen, der long ulong implizit in einen oder mehrere dieser Typen konvertiert werden muss.Furthermore, the argument_list of an array access is not allowed to contain named arguments.The number of expressions in the argument_list must be the same as the rank of the array_type, and each expression must be of type int, uint, long, ulong, or must be implicitly convertible to one or more of these types.

Das Ergebnis der Auswertung eines Array Zugriffs ist eine Variable des Elementtyps des Arrays, d. h. das Array Element, das von den Werten der Ausdrücke im argument_list ausgewählt wird.The result of evaluating an array access is a variable of the element type of the array, namely the array element selected by the value(s) of the expression(s) in the argument_list.

Die Lauf Zeit Verarbeitung eines Array Zugriffs auf das Formular P[A] , wobei P eine primary_no_array_creation_expression eines array_type und A eine argument_list ist, besteht aus den folgenden Schritten:The run-time processing of an array access of the form P[A], where P is a primary_no_array_creation_expression of an array_type and A is an argument_list, consists of the following steps:

  • P wird ausgewertet.P is evaluated. Wenn diese Auswertung eine Ausnahme verursacht, werden keine weiteren Schritte ausgeführt.If this evaluation causes an exception, no further steps are executed.
  • Die Index Ausdrücke der argument_list werden in der Reihenfolge von links nach rechts ausgewertet.The index expressions of the argument_list are evaluated in order, from left to right. Nach der Auswertung der einzelnen Index Ausdrücke wird eine implizite Konvertierung (implizite Konvertierungen) in einen der folgenden Typen ausgeführt: int , uint , long , ulong .Following evaluation of each index expression, an implicit conversion (Implicit conversions) to one of the following types is performed: int, uint, long, ulong. Der erste Typ in dieser Liste, für den eine implizite Konvertierung vorhanden ist, wird ausgewählt.The first type in this list for which an implicit conversion exists is chosen. Wenn der Index Ausdruck beispielsweise vom Typ ist, short wird eine implizite Konvertierung in int durchgeführt, da implizite Konvertierungen von short in int und von short in long möglich sind.For instance, if the index expression is of type short then an implicit conversion to int is performed, since implicit conversions from short to int and from short to long are possible. Wenn die Auswertung eines Index Ausdrucks oder der nachfolgenden impliziten Konvertierung eine Ausnahme verursacht, werden keine weiteren Index Ausdrücke ausgewertet, und es werden keine weiteren Schritte ausgeführt.If evaluation of an index expression or the subsequent implicit conversion causes an exception, then no further index expressions are evaluated and no further steps are executed.
  • Der Wert von P wird als gültig geprüft.The value of P is checked to be valid. Wenn der Wert von P ist null , wird eine ausgelöst, System.NullReferenceException und es werden keine weiteren Schritte ausgeführt.If the value of P is null, a System.NullReferenceException is thrown and no further steps are executed.
  • Der Wert jedes Ausdrucks im argument_list wird anhand der tatsächlichen Begrenzungen der einzelnen Dimensionen der Array Instanz überprüft, auf die von verwiesen wird P .The value of each expression in the argument_list is checked against the actual bounds of each dimension of the array instance referenced by P. Wenn mindestens ein Wert außerhalb des gültigen Bereichs liegt, wird eine ausgelöst, System.IndexOutOfRangeException und es werden keine weiteren Schritte ausgeführt.If one or more values are out of range, a System.IndexOutOfRangeException is thrown and no further steps are executed.
  • Der Speicherort des Array Elements, das durch den Index Ausdruck (n) angegeben wird, wird berechnet, und dieser Speicherort wird zum Ergebnis des Array Zugriffs.The location of the array element given by the index expression(s) is computed, and this location becomes the result of the array access.

IndexerzugriffIndexer access

Für einen Indexer-Zugriff muss die primary_no_array_creation_expression der element_access eine Variable oder ein Wert einer Klasse, Struktur oder eines Schnittstellen Typs sein, und dieser Typ muss einen oder mehrere Indexer implementieren, die in Bezug auf die argument_list der element_access anwendbar sind.For an indexer access, the primary_no_array_creation_expression of the element_access must be a variable or value of a class, struct, or interface type, and this type must implement one or more indexers that are applicable with respect to the argument_list of the element_access.

Die Bindungs Zeit Verarbeitung eines Indexer-Zugriffs auf das Formular P[A] , wobei P eine primary_no_array_creation_expression einer Klasse, einer Struktur oder eines Schnittstellen Typs ist T und A eine argument_list ist, besteht aus den folgenden Schritten:The binding-time processing of an indexer access of the form P[A], where P is a primary_no_array_creation_expression of a class, struct, or interface type T, and A is an argument_list, consists of the following steps:

  • Der von bereitgestellte Indexer-Satz T wird erstellt.The set of indexers provided by T is constructed. Der Satz besteht aus allen indexermembern, die in deklariert T werden, oder einem Basistyp von T , die keine override Deklarationen sind und auf die im aktuellen Kontext zugegriffen werden kann (Member Access).The set consists of all indexers declared in T or a base type of T that are not override declarations and are accessible in the current context (Member access).
  • Der Satz wird auf die Indexer reduziert, die anwendbar sind und von anderen Indexer nicht ausgeblendet werden.The set is reduced to those indexers that are applicable and not hidden by other indexers. Die folgenden Regeln werden auf jeden Indexer S.I im Satz angewendet, wobei S der Typ ist, in dem der Indexer I deklariert ist:The following rules are applied to each indexer S.I in the set, where S is the type in which the indexer I is declared:
    • Wenn I nicht in Bezug auf A (anwendbares Funktionsmember) anwendbar ist, I wird aus dem Satz entfernt.If I is not applicable with respect to A (Applicable function member), then I is removed from the set.
    • Wenn in I Bezug auf A (anwendbares Funktionsmember) anwendbar ist, werden alle in einem Basistyp von deklarierten Indexer S aus dem Satz entfernt.If I is applicable with respect to A (Applicable function member), then all indexers declared in a base type of S are removed from the set.
    • Wenn in I Bezug auf A (anwendbares Funktionsmember) anwendbar ist und S ein anderer Klassentyp als ist object , werden alle in einer Schnittstelle deklarierten Indexer aus dem Satz entfernt.If I is applicable with respect to A (Applicable function member) and S is a class type other than object, all indexers declared in an interface are removed from the set.
  • Wenn der resultierende Satz von Kandidaten Indexer leer ist, sind keine anwendbaren Indexer vorhanden, und es tritt ein Bindungs Zeitfehler auf.If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
  • Der beste Indexer der Gruppe von Kandidaten Indexern wird mithilfe der Regeln zur Überladungs Auflösung der Überladungs Auflösungidentifiziert.The best indexer of the set of candidate indexers is identified using the overload resolution rules of Overload resolution. Wenn ein einzelner optimaler Indexer nicht identifiziert werden kann, ist der Indexerzugriff mehrdeutig, und es tritt ein Fehler bei der Bindung auf.If a single best indexer cannot be identified, the indexer access is ambiguous, and a binding-time error occurs.
  • Die Index Ausdrücke der argument_list werden in der Reihenfolge von links nach rechts ausgewertet.The index expressions of the argument_list are evaluated in order, from left to right. Das Ergebnis der Verarbeitung des Indexer-Zugriffs ist ein Ausdruck, der als Indexer-Zugriff klassifiziert ist.The result of processing the indexer access is an expression classified as an indexer access. Der indexerzugriffsausdruck verweist auf den Indexer, der im obigen Schritt festgelegt wurde, und verfügt über einen zugeordneten Instanzausdruck P und eine zugeordnete Argumentliste von A .The indexer access expression references the indexer determined in the step above, and has an associated instance expression of P and an associated argument list of A.

Abhängig vom Kontext, in dem Sie verwendet werden, bewirkt ein Indexer-Zugriff, dass entweder der Get-Accessor oder der Set-Accessor des Indexers aufgerufen wird.Depending on the context in which it is used, an indexer access causes invocation of either the get accessor or the set accessor of the indexer. Wenn der Indexer-Zugriff das Ziel einer Zuweisung ist, wird der Set-Accessor aufgerufen, um einen neuen Wert zuzuweisen (einfache Zuweisung).If the indexer access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). In allen anderen Fällen wird der Get-Accessor aufgerufen, um den aktuellen Wert zu erhalten (Werte von Ausdrücken).In all other cases, the get accessor is invoked to obtain the current value (Values of expressions).

Dieser ZugriffThis access

Ein this_access besteht aus dem reservierten Wort this .A this_access consists of the reserved word this.

this_access
    : 'this'
    ;

Eine this_access ist nur im- Block eines Instanzkonstruktors, einer Instanzmethode oder eines Instanzaccessors zulässig.A this_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Dies hat eine der folgenden Bedeutungen:It has one of the following meanings:

  • Wenn this in einer primary_expression in einem Instanzkonstruktor einer Klasse verwendet wird, wird Sie als Wert klassifiziert.When this is used in a primary_expression within an instance constructor of a class, it is classified as a value. Der Typ des Werts ist der Instanztyp (der Instanztyp) der Klasse, in der die Verwendung erfolgt, und der Wert ist ein Verweis auf das Objekt, das erstellt wird.The type of the value is the instance type (The instance type) of the class within which the usage occurs, and the value is a reference to the object being constructed.
  • Wenn this in einer primary_expression in einer Instanzmethode oder einem Instanzaccessor einer Klasse verwendet wird, wird Sie als Wert klassifiziert.When this is used in a primary_expression within an instance method or instance accessor of a class, it is classified as a value. Der Typ des Werts ist der Instanztyp (der Instanztyp) der Klasse, in der die Verwendung erfolgt, und der Wert ist ein Verweis auf das Objekt, für das die Methode oder der Accessor aufgerufen wurde.The type of the value is the instance type (The instance type) of the class within which the usage occurs, and the value is a reference to the object for which the method or accessor was invoked.
  • Wenn this in einem primary_expression innerhalb eines Instanzkonstruktors einer Struktur verwendet wird, wird es als Variable klassifiziert.When this is used in a primary_expression within an instance constructor of a struct, it is classified as a variable. Der Typ der Variablen ist der Instanztyp (der Instanztyp) der Struktur, in der die Verwendung erfolgt, und die Variable stellt die Struktur dar, die erstellt wird.The type of the variable is the instance type (The instance type) of the struct within which the usage occurs, and the variable represents the struct being constructed. Die this Variable eines Instanzkonstruktors einer Struktur verhält sich genau wie ein out Parameter des Struktur Typs – Dies bedeutet insbesondere, dass die Variable definitiv in jedem Ausführungs Pfad des Instanzkonstruktors zugewiesen werden muss.The this variable of an instance constructor of a struct behaves exactly the same as an out parameter of the struct type—in particular, this means that the variable must be definitely assigned in every execution path of the instance constructor.
  • Wenn this in einer primary_expression in einer Instanzmethode oder einem Instanzaccessor einer Struktur verwendet wird, wird Sie als Variable klassifiziert.When this is used in a primary_expression within an instance method or instance accessor of a struct, it is classified as a variable. Der Typ der Variablen ist der Instanztyp (der Instanztyp) der Struktur, in der die Verwendung erfolgt.The type of the variable is the instance type (The instance type) of the struct within which the usage occurs.
    • Wenn die Methode oder der Accessor kein Iterator (Iteratoren) ist, this stellt die Variable die Struktur dar, für die die Methode oder der Accessor aufgerufen wurde, und verhält sich genau wie ein ref Parameter des Struktur Typs.If the method or accessor is not an iterator (Iterators), the this variable represents the struct for which the method or accessor was invoked, and behaves exactly the same as a ref parameter of the struct type.
    • Wenn es sich bei der Methode oder dem Accessor um einen Iterator handelt, this stellt die Variable eine Kopie der Struktur dar, für die die Methode oder der Accessor aufgerufen wurde, und verhält sich genau wie ein Wert Parameter des Struktur Typs.If the method or accessor is an iterator, the this variable represents a copy of the struct for which the method or accessor was invoked, and behaves exactly the same as a value parameter of the struct type.

Die Verwendung von this in einem primary_expression in einem anderen als dem oben aufgeführten Kontext ist ein Kompilierzeitfehler.Use of this in a primary_expression in a context other than the ones listed above is a compile-time error. Insbesondere ist es nicht möglich, auf this eine statische Methode, einen statischen Eigenschafts Accessor oder eine variable_initializer einer Feld Deklaration zu verweisen.In particular, it is not possible to refer to this in a static method, a static property accessor, or in a variable_initializer of a field declaration.

Basis ZugriffBase access

Ein base_access besteht aus dem reservierten Wort, base gefolgt von einem " . "-Token und einem-Bezeichner oder einem in eckige Klammern eingeschlossenen argument_list :A base_access consists of the reserved word base followed by either a "." token and an identifier or an argument_list enclosed in square brackets:

base_access
    : 'base' '.' identifier
    | 'base' '[' expression_list ']'
    ;

Ein base_access wird für den Zugriff auf Basisklassenmember verwendet, die durch ähnlich benannte Member in der aktuellen Klasse oder Struktur ausgeblendet werden.A base_access is used to access base class members that are hidden by similarly named members in the current class or struct. Eine base_access ist nur im- Block eines Instanzkonstruktors, einer Instanzmethode oder eines Instanzaccessors zulässig.A base_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Wenn base.I in einer Klasse oder Struktur vorkommt, I muss einen Member der Basisklasse dieser Klasse oder Struktur bezeichnen.When base.I occurs in a class or struct, I must denote a member of the base class of that class or struct. Ebenso muss bei base[E] Auftreten von in einer Klasse ein anwendbarer Indexer in der Basisklasse vorhanden sein.Likewise, when base[E] occurs in a class, an applicable indexer must exist in the base class.

Bei der Bindungs Zeit werden base_access Ausdrücke des Formulars base.I und genauso base[E] ausgewertet, als wären Sie geschrieben worden ((B)this).I ((B)this)[E] , wobei B die Basisklasse der Klasse oder Struktur ist, in der das Konstrukt auftritt.At binding-time, base_access expressions of the form base.I and base[E] are evaluated exactly as if they were written ((B)this).I and ((B)this)[E], where B is the base class of the class or struct in which the construct occurs. Folglich base.I entsprechen und und base[E] this.I this[E] , außer this als Instanz der Basisklasse.Thus, base.I and base[E] correspond to this.I and this[E], except this is viewed as an instance of the base class.

Wenn eine base_access auf einen virtuellen Funktionsmember (eine Methode, eine Eigenschaft oder einen Indexer) verweist, wird bestimmt, welcher Funktionsmember zur Laufzeit aufgerufen werden soll (über Prüfung der Auflösung der dynamischen Überlastung).When a base_access references a virtual function member (a method, property, or indexer), the determination of which function member to invoke at run-time (Compile-time checking of dynamic overload resolution) is changed. Der aufgerufene Funktionsmember wird ermittelt, indem die am meisten abgeleitete Implementierung (virtuelle Methoden) des Funktionsmembers in Bezug auf B (anstelle des Lauf Zeit Typs this , wie bei einem nicht-Basis-Zugriff üblich) gefunden wird.The function member that is invoked is determined by finding the most derived implementation (Virtual methods) of the function member with respect to B (instead of with respect to the run-time type of this, as would be usual in a non-base access). Daher override virtual kann ein base_access in einem eines Funktionsmembers verwendet werden, um die geerbte Implementierung des Funktionsmembers aufzurufen.Thus, within an override of a virtual function member, a base_access can be used to invoke the inherited implementation of the function member. Wenn das von einem base_access referenzierte Funktionsmember abstrakt ist, tritt ein Fehler bei der Bindung auf.If the function member referenced by a base_access is abstract, a binding-time error occurs.

Postfix-Inkrementoperator und Postfix-DekrementoperatorPostfix increment and decrement operators

post_increment_expression
    : primary_expression '++'
    ;

post_decrement_expression
    : primary_expression '--'
    ;

Der Operand eines Postfix-Inkrement-oder dekrementvorgangs muss ein Ausdruck sein, der als Variable, Eigenschafts Zugriff oder Indexerzugriff klassifiziert ist.The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Das Ergebnis des Vorgangs ist ein Wert desselben Typs wie der Operand.The result of the operation is a value of the same type as the operand.

Wenn das primary_expression den Kompilier Zeittyp aufweist dynamic , wird der Operator dynamisch gebunden (dynamische Bindung), die post_increment_expression oder post_decrement_expression den Kompilier Zeittyp, dynamic und die folgenden Regeln werden zur Laufzeit mithilfe des Lauf Zeit Typs der primary_expression angewendet.If the primary_expression has the compile-time type dynamic then the operator is dynamically bound (Dynamic binding), the post_increment_expression or post_decrement_expression has the compile-time type dynamic and the following rules are applied at run-time using the run-time type of the primary_expression.

Wenn der Operand einer Postfix-Inkrement-oder Dekrementoperation eine Eigenschaft oder ein Indexer-Zugriff ist, muss die Eigenschaft oder der Indexer sowohl einen get -als auch einen- set Accessor aufweisen.If the operand of a postfix increment or decrement operation is a property or indexer access, the property or indexer must have both a get and a set accessor. Wenn dies nicht der Fall ist, tritt ein Bindungs Zeitfehler auf.If this is not the case, a binding-time error occurs.

Unäre Operator Überladungs Auflösung (unäre Operator Überladungs Auflösung) wird angewendet, um eine bestimmte Operator Implementierung auszuwählen.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. ++ -- Für die folgenden Typen sind vordefinierte-und-Operatoren vorhanden: sbyte , byte , short , ushort , int , uint , long , ulong , char , float , double , decimal und ein beliebiger Enumerationstyp.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Die vordefinierten ++ Operatoren geben den Wert zurück, der beim Hinzufügen von 1 zum Operanden erzeugt wurde, und die vordefinierten -- Operatoren geben den Wert zurück, der durch die Subtraktion von 1 vom Operanden erzeugt wird.The predefined ++ operators return the value produced by adding 1 to the operand, and the predefined -- operators return the value produced by subtracting 1 from the operand. Wenn in einem checked Kontext das Ergebnis dieser Addition oder Subtraktion außerhalb des Bereichs des Ergebnis Typs liegt und der Ergebnistyp ein ganzzahliger Typ oder Enumeration-Typ ist, System.OverflowException wird eine ausgelöst.In a checked context, if the result of this addition or subtraction is outside the range of the result type and the result type is an integral type or enum type, a System.OverflowException is thrown.

Die Lauf Zeit Verarbeitung einer Postfix-Inkrement-oder Dekrementoperation des Formulars x++ oder x-- besteht aus den folgenden Schritten:The run-time processing of a postfix increment or decrement operation of the form x++ or x-- consists of the following steps:

  • Wenn x als Variable klassifiziert ist:If x is classified as a variable:
    • x wird ausgewertet, um die Variable zu entwickeln.x is evaluated to produce the variable.
    • Der Wert von x wird gespeichert.The value of x is saved.
    • Der ausgewählte Operator wird mit dem gespeicherten Wert von x als sein Argument aufgerufen.The selected operator is invoked with the saved value of x as its argument.
    • Der vom-Operator zurückgegebene Wert wird an dem Speicherort gespeichert, der durch die Auswertung von angegeben wird x .The value returned by the operator is stored in the location given by the evaluation of x.
    • Der gespeicherte Wert von x wird das Ergebnis des Vorgangs.The saved value of x becomes the result of the operation.
  • Wenn x als Eigenschaft oder Indexer-Zugriff klassifiziert ist:If x is classified as a property or indexer access:
    • Der Instanzausdruck (wenn x nicht ist static ), und die Argumentliste (wenn x ein Indexer-Zugriff ist), die zugeordnet ist x , wird ausgewertet, und die Ergebnisse werden in den nachfolgenden get -und-Accessoraufrufen verwendet set .The instance expression (if x is not static) and the argument list (if x is an indexer access) associated with x are evaluated, and the results are used in the subsequent get and set accessor invocations.
    • Der get -Accessor von x wird aufgerufen, und der zurückgegebene Wert wird gespeichert.The get accessor of x is invoked and the returned value is saved.
    • Der ausgewählte Operator wird mit dem gespeicherten Wert von x als sein Argument aufgerufen.The selected operator is invoked with the saved value of x as its argument.
    • Der- set Accessor von x wird mit dem Wert aufgerufen, der vom Operator als sein Argument zurückgegeben wurde value .The set accessor of x is invoked with the value returned by the operator as its value argument.
    • Der gespeicherte Wert von x wird das Ergebnis des Vorgangs.The saved value of x becomes the result of the operation.

Die ++ -- Operatoren und unterstützen auch Präfix Notation (Präfix Inkrement-und Dekrementoperatoren).The ++ and -- operators also support prefix notation (Prefix increment and decrement operators). In der Regel ist das Ergebnis von x++ oder x-- der Wert von x vor dem Vorgang, wohingegen das Ergebnis von ++x oder --x der Wert von x nach dem Vorgang ist.Typically, the result of x++ or x-- is the value of x before the operation, whereas the result of ++x or --x is the value of x after the operation. In jedem Fall x hat nach dem Vorgang denselben Wert.In either case, x itself has the same value after the operation.

Eine- operator ++ oder- operator -- Implementierung kann entweder mithilfe der Postfix-oder Präfix Notation aufgerufen werden.An operator ++ or operator -- implementation can be invoked using either postfix or prefix notation. Es ist nicht möglich, separate Operator Implementierungen für die beiden Notationen zu haben.It is not possible to have separate operator implementations for the two notations.

Der new-OperatorThe new operator

Der- new Operator wird verwendet, um neue Instanzen von-Typen zu erstellen.The new operator is used to create new instances of types.

Es gibt drei Formen von new Ausdrücken:There are three forms of new expressions:

  • Objekt Erstellungs Ausdrücke werden verwendet, um neue Instanzen von Klassentypen und Werttypen zu erstellen.Object creation expressions are used to create new instances of class types and value types.
  • Array Erstellungs Ausdrücke werden verwendet, um neue Instanzen von Array Typen zu erstellen.Array creation expressions are used to create new instances of array types.
  • Delegaterstellungs-Ausdrücke werden verwendet, um neue Instanzen von Delegattypen zu erstellen.Delegate creation expressions are used to create new instances of delegate types.

Der new Operator impliziert die Erstellung einer Instanz eines Typs, impliziert jedoch nicht notwendigerweise die dynamische Speicher Belegung.The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. Vor allem sind für Instanzen von Werttypen außerhalb der Variablen, in denen Sie sich befinden, kein zusätzlicher Arbeitsspeicher erforderlich. es treten keine dynamischen Zuordnungen auf, wenn new zum Erstellen von Instanzen von Werttypen verwendet wird.In particular, instances of value types require no additional memory beyond the variables in which they reside, and no dynamic allocations occur when new is used to create instances of value types.

Objekt Erstellungs AusdrückeObject creation expressions

Eine object_creation_expression wird zum Erstellen einer neuen Instanz einer class_type oder einer value_type verwendet.An object_creation_expression is used to create a new instance of a class_type or a value_type.

object_creation_expression
    : 'new' type '(' argument_list? ')' object_or_collection_initializer?
    | 'new' type object_or_collection_initializer
    ;

object_or_collection_initializer
    : object_initializer
    | collection_initializer
    ;

Der Typ eines object_creation_expression muss ein class_type, ein value_type oder ein type_parameter sein.The type of an object_creation_expression must be a class_type, a value_type or a type_parameter. Der Typ darf keine abstract class_type sein.The type cannot be an abstract class_type.

Die optionalen argument_list (Argumentlisten) sind nur zulässig, wenn es sich bei dem Typ um einen class_type oder eine struct_type handelt.The optional argument_list (Argument lists) is permitted only if the type is a class_type or a struct_type.

Ein Objekt Erstellungs Ausdruck kann die Liste der Konstruktorargumente weglassen und einschließende Klammern einschließen, wenn er einen Objektinitialisierer oder einen Auflistungsinitialisierer enthält.An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. Das Weglassen der Konstruktorargumentliste und das Einschließen von Klammern entspricht der Angabe einer leeren Argumentliste.Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.

Die Verarbeitung eines Ausdrucks zur Objekt Erstellung, der einen Objektinitialisierer oder Auflistungsinitialisierer enthält, besteht aus der ersten Verarbeitung des Instanzkonstruktors und der anschließenden Verarbeitung der Element-oder Element Initialisierungen, die vom Objektinitialisierer (Objektinitialisierer) oder sammlungsinitialisierer (sammlungsinitialisiererProcessing of an object creation expression that includes an object initializer or collection initializer consists of first processing the instance constructor and then processing the member or element initializations specified by the object initializer (Object initializers) or collection initializer (Collection initializers).

Wenn eines der Argumente im optionalen argument_list den Kompilier Zeittyp aufweist dynamic , wird der object_creation_expression dynamisch gebunden (dynamische Bindung), und die folgenden Regeln werden zur Laufzeit verwendet, wobei der Lauf Zeittyp der Argumente der argument_list , die den Kompilier Zeittyp aufweisen, verwendet wird dynamic .If any of the arguments in the optional argument_list has the compile-time type dynamic then the object_creation_expression is dynamically bound (Dynamic binding) and the following rules are applied at run-time using the run-time type of those arguments of the argument_list that have the compile time type dynamic. Allerdings wird bei der Objekt Erstellung eine beschränkte Kompilierungszeit Überprüfung durchgeführt, wie in der Kompilierzeit Überprüfung der dynamischen Überladungs Auflösungbeschrieben.However, the object creation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

Die Bindungs Zeit Verarbeitung einer object_creation_expression der Form new T(A) , wobei T ein class_type oder ein value_type ist und A ein optionaler argument_list ist, besteht aus den folgenden Schritten:The binding-time processing of an object_creation_expression of the form new T(A), where T is a class_type or a value_type and A is an optional argument_list, consists of the following steps:

  • Wenn T ein value_type ist und A nicht vorhanden ist:If T is a value_type and A is not present:
    • Der object_creation_expression ist ein standardkonstruktoraufruf.The object_creation_expression is a default constructor invocation. Das Ergebnis der object_creation_expression ist ein Wert vom Typ T , d. h. der Standardwert für, T wie im System. ValueType-Typdefiniert.The result of the object_creation_expression is a value of type T, namely the default value for T as defined in The System.ValueType type.
  • Andernfalls, wenn T ein type_parameter ist und A nicht vorhanden ist:Otherwise, if T is a type_parameter and A is not present:
    • Wenn keine Werttyp Einschränkung oder Konstruktoreinschränkung (Typparameter Einschränkungen) für angegeben wurde T , tritt ein Bindungs Zeitfehler auf.If no value type constraint or constructor constraint (Type parameter constraints) has been specified for T, a binding-time error occurs.
    • Das Ergebnis der object_creation_expression ist ein Wert des Lauf Zeittyps, an den der Typparameter gebunden wurde, nämlich das Ergebnis des Aufrufs des Standardkonstruktors dieses Typs.The result of the object_creation_expression is a value of the run-time type that the type parameter has been bound to, namely the result of invoking the default constructor of that type. Der Lauf Zeittyp kann ein Referenztyp oder ein Werttyp sein.The run-time type may be a reference type or a value type.
  • Andernfalls, wenn T ein class_type oder ein struct_type ist:Otherwise, if T is a class_type or a struct_type:
    • Wenn T ein abstract class_type ist, tritt ein Kompilierzeitfehler auf.If T is an abstract class_type, a compile-time error occurs.
    • Der aufzurufende Instanzkonstruktor wird mithilfe der Regeln zur Überladungs Auflösung der Überladungs Auflösungbestimmt.The instance constructor to invoke is determined using the overload resolution rules of Overload resolution. Der Satz von Kandidaten Instanzkonstruktoren besteht aus allen zugänglichen Instanzkonstruktoren T , die in deklariert sind und in Bezug auf A (anwendbares Funktionsmember) anwendbar sind.The set of candidate instance constructors consists of all accessible instance constructors declared in T which are applicable with respect to A (Applicable function member). Wenn der Satz von standardinstanzkonstruktoren leer ist, oder wenn ein einzelner Konstruktor mit der besten Instanz nicht identifiziert werden kann, tritt ein Bindungs Zeitfehler auf.If the set of candidate instance constructors is empty, or if a single best instance constructor cannot be identified, a binding-time error occurs.
    • Das Ergebnis der object_creation_expression ist ein Wert vom Typ T , d. h. der Wert, der durch Aufrufen des Instanzkonstruktors erzeugt wird, der im obigen Schritt festgelegt wurde.The result of the object_creation_expression is a value of type T, namely the value produced by invoking the instance constructor determined in the step above.
  • Andernfalls ist der object_creation_expression ungültig, und ein Bindungs Fehler tritt auf.Otherwise, the object_creation_expression is invalid, and a binding-time error occurs.

Auch wenn die object_creation_expression dynamisch gebunden ist, ist der Kompilier Zeittyp immer noch T .Even if the object_creation_expression is dynamically bound, the compile-time type is still T.

Die Lauf Zeit Verarbeitung einer object_creation_expression der Form new T(A) , wobei T class_type oder ein struct_type ist und A eine optionale argument_list ist, besteht aus den folgenden Schritten:The run-time processing of an object_creation_expression of the form new T(A), where T is class_type or a struct_type and A is an optional argument_list, consists of the following steps:

  • Wenn T ein class_type ist:If T is a class_type:
    • Es wird eine neue Instanz der-Klasse T zugeordnet.A new instance of class T is allocated. Wenn nicht genügend Arbeitsspeicher zur Verfügung steht, um die neue Instanz zuzuordnen, wird eine ausgelöst, System.OutOfMemoryException und es werden keine weiteren Schritte ausgeführt.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • Alle Felder der neuen Instanz werden mit ihren Standardwerten initialisiert (Standardwerte).All fields of the new instance are initialized to their default values (Default values).
    • Der Instanzkonstruktor wird entsprechend den Regeln für den Funktionselement Aufruf (Kompilierzeit Überprüfung der dynamischen Überladungs Auflösung) aufgerufen.The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Ein Verweis auf die neu zugeordnete-Instanz wird automatisch an den Instanzkonstruktor übergeben, und der Zugriff auf die-Instanz kann innerhalb dieses Konstruktors als erfolgen this .A reference to the newly allocated instance is automatically passed to the instance constructor and the instance can be accessed from within that constructor as this.
  • Wenn T ein struct_type ist:If T is a struct_type:
    • Eine Instanz vom Typ T wird erstellt, indem eine temporäre lokale Variable zugewiesen wird.An instance of type T is created by allocating a temporary local variable. Da ein Instanzkonstruktor einer struct_type erforderlich ist, um jedem Feld der erstellten Instanz einen Wert definitiv zuzuweisen, ist keine Initialisierung der temporären Variablen erforderlich.Since an instance constructor of a struct_type is required to definitely assign a value to each field of the instance being created, no initialization of the temporary variable is necessary.
    • Der Instanzkonstruktor wird entsprechend den Regeln für den Funktionselement Aufruf (Kompilierzeit Überprüfung der dynamischen Überladungs Auflösung) aufgerufen.The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Ein Verweis auf die neu zugeordnete-Instanz wird automatisch an den Instanzkonstruktor übergeben, und der Zugriff auf die-Instanz kann innerhalb dieses Konstruktors als erfolgen this .A reference to the newly allocated instance is automatically passed to the instance constructor and the instance can be accessed from within that constructor as this.

ObjektinitialisiererObject initializers

Ein Objektinitialisierer gibt Werte für NULL oder mehr Felder, Eigenschaften oder indizierte Elemente eines Objekts an.An object initializer specifies values for zero or more fields, properties or indexed elements of an object.

object_initializer
    : '{' member_initializer_list? '}'
    | '{' member_initializer_list ',' '}'
    ;

member_initializer_list
    : member_initializer (',' member_initializer)*
    ;

member_initializer
    : initializer_target '=' initializer_value
    ;

initializer_target
    : identifier
    | '[' argument_list ']'
    ;

initializer_value
    : expression
    | object_or_collection_initializer
    ;

Ein Objektinitialisierer besteht aus einer Sequenz von Elementinitialisierern, die von { -und- } Token eingeschlossen und durch Kommas getrennt sind.An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas. Jede member_initializer bestimmt ein Ziel für die Initialisierung.Each member_initializer designates a target for the initialization. Ein Bezeichner muss ein barrierefreies Feld oder eine Eigenschaft des Objekts benennen, das initialisiert wird, wohingegen eine in eckige Klammern eingeschlossene argument_list Argumente für einen zugreif baren Indexer für das Objekt angeben muss, das initialisiert wird.An identifier must name an accessible field or property of the object being initialized, whereas an argument_list enclosed in square brackets must specify arguments for an accessible indexer on the object being initialized. Es ist ein Fehler, wenn ein Objektinitialisierer mehr als einen Elementinitialisierer für das gleiche Feld oder die gleiche Eigenschaft einschließt.It is an error for an object initializer to include more than one member initializer for the same field or property.

Auf jede initializer_target folgt ein Gleichheitszeichen und entweder ein Ausdruck, ein Objektinitialisierer oder ein Auflistungsinitialisierer.Each initializer_target is followed by an equals sign and either an expression, an object initializer or a collection initializer. Es ist nicht möglich, dass Ausdrücke im Objektinitialisierer auf das neu erstellte Objekt verweisen, das initialisiert wird.It is not possible for expressions within the object initializer to refer to the newly created object it is initializing.

Ein Member-Initialisierer, der einen Ausdruck angibt, nachdem das Gleichheitszeichen auf die gleiche Weise wie eine Zuweisung (einfache Zuweisung) zum Ziel verarbeitet wird.A member initializer that specifies an expression after the equals sign is processed in the same way as an assignment (Simple assignment) to the target.

Ein Member-Initialisierer, der einen Objektinitialisierer angibt, nachdem das Gleichheitszeichen ein instanzinitialisierer ist, d. h. eine Initialisierung eines eingebetteten Objekts.A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. Anstatt dem Feld oder der Eigenschaft einen neuen Wert zuzuweisen, werden die Zuweisungen im Initialisierer für den initialisierten Objektinitialisierer als Zuweisungen zu Membern des Felds oder der Eigenschaft behandelt.Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Initialisierer für ein Objekt können nicht auf Eigenschaften mit einem Werttyp oder auf schreibgeschützte Felder mit einem Werttyp angewendet werden.Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.

Ein Member-Initialisierer, der einen Auflistungsinitialisierer angibt, nachdem das Gleichheitszeichen eine Initialisierung einer eingebetteten Auflistung ist.A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Anstatt dem Zielfeld, der Eigenschaft oder dem Indexer eine neue Auflistung zuzuweisen, werden die im Initialisierer angegebenen Elemente der Auflistung hinzugefügt, auf die das Ziel verweist.Instead of assigning a new collection to the target field, property or indexer, the elements given in the initializer are added to the collection referenced by the target. Das Ziel muss einen Sammlungstyp aufweisen, der die in Auflistungsinitialisierer angegebenen Anforderungen erfüllt. The target must be of a collection type that satisfies the requirements specified in Collection initializers.

Die Argumente für einen indexinitialisierer werden immer genau einmal ausgewertet.The arguments to an index initializer will always be evaluated exactly once. Folglich werden Sie, selbst wenn die Argumente am Ende nie verwendet werden (z. b. aufgrund eines leeren Initialisierers), auf Ihre Nebeneffekte ausgewertet.Thus, even if the arguments end up never getting used (e.g. because of an empty nested initializer), they will be evaluated for their side effects.

Die folgende Klasse stellt einen Punkt mit zwei Koordinaten dar:The following class represents a point with two coordinates:

public class Point
{
    int x, y;

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

Eine Instanz von Point kann wie folgt erstellt und initialisiert werden:An instance of Point can be created and initialized as follows:

Point a = new Point { X = 0, Y = 1 };

Dies hat die gleiche Wirkung wiewhich has the same effect as

Point __a = new Point();
__a.X = 0;
__a.Y = 1; 
Point a = __a;

dabei __a ist eine anderweitig unsichtbare und nicht zugängliche temporäre Variable.where __a is an otherwise invisible and inaccessible temporary variable. Die folgende Klasse stellt ein Rechteck dar, das aus zwei Punkten erstellt wurde:The following class represents a rectangle created from two points:

public class Rectangle
{
    Point p1, p2;

    public Point P1 { get { return p1; } set { p1 = value; } }
    public Point P2 { get { return p2; } set { p2 = value; } }
}

Eine Instanz von Rectangle kann wie folgt erstellt und initialisiert werden:An instance of Rectangle can be created and initialized as follows:

Rectangle r = new Rectangle {
    P1 = new Point { X = 0, Y = 1 },
    P2 = new Point { X = 2, Y = 3 }
};

Dies hat die gleiche Wirkung wiewhich has the same effect as

Rectangle __r = new Rectangle();
Point __p1 = new Point();
__p1.X = 0;
__p1.Y = 1;
__r.P1 = __p1;
Point __p2 = new Point();
__p2.X = 2;
__p2.Y = 3;
__r.P2 = __p2; 
Rectangle r = __r;

dabei __r __p1 handelt es sich bei und __p2 um temporäre Variablen, die andernfalls unsichtbar und nicht zugänglich sind.where __r, __p1 and __p2 are temporary variables that are otherwise invisible and inaccessible.

, Wenn Rectangle der Konstruktor die beiden eingebetteten Instanzen ordnet. PointIf Rectangle's constructor allocates the two embedded Point instances

public class Rectangle
{
    Point p1 = new Point();
    Point p2 = new Point();

    public Point P1 { get { return p1; } }
    public Point P2 { get { return p2; } }
}

Das folgende Konstrukt kann verwendet werden, um die eingebetteten Instanzen zu initialisieren, Point anstatt neue Instanzen zuzuweisen:the following construct can be used to initialize the embedded Point instances instead of assigning new instances:

Rectangle r = new Rectangle {
    P1 = { X = 0, Y = 1 },
    P2 = { X = 2, Y = 3 }
};

Dies hat die gleiche Wirkung wiewhich has the same effect as

Rectangle __r = new Rectangle();
__r.P1.X = 0;
__r.P1.Y = 1;
__r.P2.X = 2;
__r.P2.Y = 3;
Rectangle r = __r;

Im folgenden Beispiel wird eine entsprechende Definition von C angegeben:Given an appropriate definition of C, the following example:

var c = new C {
    x = true,
    y = { a = "Hello" },
    z = { 1, 2, 3 },
    ["x"] = 5,
    [0,0] = { "a", "b" },
    [1,2] = {}
};

entspricht dieser Reihe von Zuweisungen:is equivalent to this series of assignments:

C __c = new C();
__c.x = true;
__c.y.a = "Hello";
__c.z.Add(1); 
__c.z.Add(2);
__c.z.Add(3);
string __i1 = "x";
__c[__i1] = 5;
int __i2 = 0, __i3 = 0;
__c[__i2,__i3].Add("a");
__c[__i2,__i3].Add("b");
int __i4 = 1, __i5 = 2;
var c = __c;

Where __c , usw., sind generierte Variablen, die unsichtbar sind und für den Quellcode nicht zugänglich sind.where __c, etc., are generated variables that are invisible and inaccessible to the source code. Beachten Sie, dass die Argumente für [0,0] nur einmal ausgewertet werden und die Argumente für [1,2] einmal ausgewertet werden, auch wenn Sie nie verwendet werden.Note that the arguments for [0,0] are evaluated only once, and the arguments for [1,2] are evaluated once even though they are never used.

AuflistungsinitialisiererCollection initializers

Ein Auflistungsinitialisierer gibt die Elemente einer Auflistung an.A collection initializer specifies the elements of a collection.

collection_initializer
    : '{' element_initializer_list '}'
    | '{' element_initializer_list ',' '}'
    ;

element_initializer_list
    : element_initializer (',' element_initializer)*
    ;

element_initializer
    : non_assignment_expression
    | '{' expression_list '}'
    ;

expression_list
    : expression (',' expression)*
    ;

Ein Auflistungsinitialisierer besteht aus einer Sequenz von Elementinitialisierern, die von { -und- } Token eingeschlossen und durch Kommas getrennt sind.A collection initializer consists of a sequence of element initializers, enclosed by { and } tokens and separated by commas. Jeder Elementinitialisierer gibt ein Element an, das dem aufzurufenden Auflistungs Objekt hinzugefügt werden soll, und besteht aus einer Liste von Ausdrücken, die von { -und- } Token eingeschlossen und durch Kommas getrennt sind.Each element initializer specifies an element to be added to the collection object being initialized, and consists of a list of expressions enclosed by { and } tokens and separated by commas. Ein Elementinitialisierer mit einem Ausdruck kann ohne geschweifte Klammern geschrieben werden, kann jedoch kein Zuweisungs Ausdruck sein, um Mehrdeutigkeit mit Member-Initialisierern zu vermeiden.A single-expression element initializer can be written without braces, but cannot then be an assignment expression, to avoid ambiguity with member initializers. Die non_assignment_expression Produktion ist in Expressiondefiniert.The non_assignment_expression production is defined in Expression.

Im folgenden finden Sie ein Beispiel für einen Objekt Erstellungs Ausdruck, der einen Auflistungsinitialisierer umfasst:The following is an example of an object creation expression that includes a collection initializer:

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Das Auflistungs Objekt, auf das ein Auflistungsinitialisierer angewendet wird, muss einen Typ aufweisen, der implementiert, System.Collections.IEnumerable oder ein Kompilierzeitfehler tritt auf.The collection object to which a collection initializer is applied must be of a type that implements System.Collections.IEnumerable or a compile-time error occurs. Für jedes angegebene Element in der Reihenfolge ruft der sammlungsinitialisierer eine Add Methode für das Zielobjekt mit der Ausdrucks Liste des elementinitialisierers als Argumentliste auf und wendet die normale Member-Suche-und Überladungs Auflösung für jeden Aufruf an.For each specified element in order, the collection initializer invokes an Add method on the target object with the expression list of the element initializer as argument list, applying normal member lookup and overload resolution for each invocation. Folglich muss das Auflistungs Objekt über eine gültige Instanz-oder Erweiterungsmethode mit dem Namen Add für jeden Elementinitialisierer verfügen.Thus, the collection object must have an applicable instance or extension method with the name Add for each element initializer.

Die folgende Klasse stellt einen Kontakt mit einem Namen und einer Liste von Telefonnummern dar:The following class represents a contact with a name and a list of phone numbers:

public class Contact
{
    string name;
    List<string> phoneNumbers = new List<string>();

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

    public List<string> PhoneNumbers { get { return phoneNumbers; } }
}

Eine List<Contact> kann wie folgt erstellt und initialisiert werden:A List<Contact> can be created and initialized as follows:

var contacts = new List<Contact> {
    new Contact {
        Name = "Chris Smith",
        PhoneNumbers = { "206-555-0101", "425-882-8080" }
    },
    new Contact {
        Name = "Bob Harris",
        PhoneNumbers = { "650-555-0199" }
    }
};

Dies hat die gleiche Wirkung wiewhich has the same effect as

var __clist = new List<Contact>();
Contact __c1 = new Contact();
__c1.Name = "Chris Smith";
__c1.PhoneNumbers.Add("206-555-0101");
__c1.PhoneNumbers.Add("425-882-8080");
__clist.Add(__c1);
Contact __c2 = new Contact();
__c2.Name = "Bob Harris";
__c2.PhoneNumbers.Add("650-555-0199");
__clist.Add(__c2);
var contacts = __clist;

dabei __clist __c1 handelt es sich bei und __c2 um temporäre Variablen, die andernfalls unsichtbar und nicht zugänglich sind.where __clist, __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.

Ausdrücke zum Erstellen von ArraysArray creation expressions

Eine array_creation_expression wird zum Erstellen einer neuen Instanz eines- array_type verwendet.An array_creation_expression is used to create a new instance of an array_type.

array_creation_expression
    : 'new' non_array_type '[' expression_list ']' rank_specifier* array_initializer?
    | 'new' array_type array_initializer
    | 'new' rank_specifier array_initializer
    ;

Ein Array Erstellungs Ausdruck des ersten Formulars ordnet eine Array Instanz des Typs zu, der sich aus dem Löschen der einzelnen Ausdrücke aus der Ausdrucks Liste ergibt.An array creation expression of the first form allocates an array instance of the type that results from deleting each of the individual expressions from the expression list. Beispielsweise erzeugt der Ausdruck für die Array Erstellung new int[10,20] eine Array Instanz vom Typ int[,] , und der Ausdruck für die Array Erstellung new int[10][,] erzeugt ein Array vom Typ int[][,] .For example, the array creation expression new int[10,20] produces an array instance of type int[,], and the array creation expression new int[10][,] produces an array of type int[][,]. Jeder Ausdruck in der Ausdrucks Liste muss vom Typ int , uint , oder sein long ulong oder implizit in einen oder mehrere dieser Typen konvertiert werden können.Each expression in the expression list must be of type int, uint, long, or ulong, or implicitly convertible to one or more of these types. Der Wert jedes Ausdrucks bestimmt die Länge der entsprechenden Dimension in der neu zugeordneten Array Instanz.The value of each expression determines the length of the corresponding dimension in the newly allocated array instance. Da die Länge einer Array Dimension nicht negativ sein muss, ist dies ein Kompilierzeitfehler, bei dem ein constant_expression mit einem negativen Wert in der Ausdrucks Liste vorliegt.Since the length of an array dimension must be nonnegative, it is a compile-time error to have a constant_expression with a negative value in the expression list.

Das Layout von Arrays ist nicht festgelegt, es sei denn, es ist ein unsicherer Kontext (unsichere Kontexte).Except in an unsafe context (Unsafe contexts), the layout of arrays is unspecified.

Wenn ein Array Erstellungs Ausdruck des ersten Formulars einen Arrayinitialisierer enthält, muss jeder Ausdruck in der Ausdrucks Liste eine Konstante sein, und die von der Ausdrucks Liste angegebenen Rang-und Dimensions Längen müssen mit denen des Arrayinitialisierers identisch sein.If an array creation expression of the first form includes an array initializer, each expression in the expression list must be a constant and the rank and dimension lengths specified by the expression list must match those of the array initializer.

In einem Array Erstellungs Ausdruck des zweiten oder dritten Formulars muss der Rang des angegebenen Arraytyps oder rangspezifizierers mit dem des Arrayinitialisierers identisch sein.In an array creation expression of the second or third form, the rank of the specified array type or rank specifier must match that of the array initializer. Die einzelnen Dimensions Längen werden von der Anzahl von Elementen in jeder der entsprechenden Schachtelungs Ebenen des Arrayinitialisierers abgeleitet.The individual dimension lengths are inferred from the number of elements in each of the corresponding nesting levels of the array initializer. Folglich ist der AusdruckThus, the expression

new int[,] {{0, 1}, {2, 3}, {4, 5}}

entspricht genauexactly corresponds to

new int[3, 2] {{0, 1}, {2, 3}, {4, 5}}

Ein Array Erstellungs Ausdruck des dritten Formulars wird als *implizit typisierter Array Erstellungs Ausdruck _ bezeichnet.An array creation expression of the third form is referred to as an *implicitly typed array creation expression _. Sie ähnelt dem zweiten Formular, mit dem Unterschied, dass der Elementtyp des Arrays nicht explizit angegeben wird, sondern als der am besten geeignete Typ (suchendes besten allgemeinen Typs eines Satzes von Ausdrücken) des Satzes von Ausdrücken im Arrayinitialisierer festgelegt ist.It is similar to the second form, except that the element type of the array is not explicitly given, but determined as the best common type (Finding the best common type of a set of expressions) of the set of expressions in the array initializer. Bei einem mehrdimensionalen Array, d. h. einer, bei dem der _rank_specifier * mindestens ein Komma enthält, besteht dieser Satz aus allen Ausdrücken, die in den array_initializer s gefunden wurden.For a multidimensional array, i.e., one where the _rank_specifier* contains at least one comma, this set comprises all expression s found in nested array_initializer s.

Arrayinitialisierer werden in arrayinitialisierernausführlicher beschrieben.Array initializers are described further in Array initializers.

Das Ergebnis der Auswertung eines Array Erstellungs Ausdrucks wird als Wert klassifiziert, nämlich als Verweis auf die neu zugeordnete Array Instanz.The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. Die Lauf Zeit Verarbeitung eines Ausdrucks zur Array Erstellung besteht aus den folgenden Schritten:The run-time processing of an array creation expression consists of the following steps:

  • Die Dimensions Längen Ausdrücke der expression_list werden in der Reihenfolge von links nach rechts ausgewertet.The dimension length expressions of the expression_list are evaluated in order, from left to right. Nach der Auswertung der einzelnen Ausdrücke wird eine implizite Konvertierung (implizite Konvertierungen) in einen der folgenden Typen ausgeführt: int , uint , long , ulong .Following evaluation of each expression, an implicit conversion (Implicit conversions) to one of the following types is performed: int, uint, long, ulong. Der erste Typ in dieser Liste, für den eine implizite Konvertierung vorhanden ist, wird ausgewählt.The first type in this list for which an implicit conversion exists is chosen. Wenn die Auswertung eines Ausdrucks oder der nachfolgenden impliziten Konvertierung eine Ausnahme verursacht, werden keine weiteren Ausdrücke ausgewertet, und es werden keine weiteren Schritte ausgeführt.If evaluation of an expression or the subsequent implicit conversion causes an exception, then no further expressions are evaluated and no further steps are executed.
  • Die berechneten Werte für die Dimensions Längen werden wie folgt überprüft.The computed values for the dimension lengths are validated as follows. Wenn mindestens einer der-Werte kleiner als 0 (null) ist, wird eine ausgelöst, System.OverflowException und es werden keine weiteren Schritte ausgeführt.If one or more of the values are less than zero, a System.OverflowException is thrown and no further steps are executed.
  • Eine Array Instanz mit den angegebenen Dimensions Längen ist zugeordnet.An array instance with the given dimension lengths is allocated. Wenn nicht genügend Arbeitsspeicher zur Verfügung steht, um die neue Instanz zuzuordnen, wird eine ausgelöst, System.OutOfMemoryException und es werden keine weiteren Schritte ausgeführt.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
  • Alle Elemente der neuen Array Instanz werden mit ihren Standardwerten initialisiert (Standardwerte).All elements of the new array instance are initialized to their default values (Default values).
  • Wenn der Ausdruck für die Array Erstellung einen Arrayinitialisierer enthält, wird jeder Ausdruck im Arrayinitialisierer ausgewertet und dem entsprechenden Array Element zugewiesen.If the array creation expression contains an array initializer, then each expression in the array initializer is evaluated and assigned to its corresponding array element. Die Auswertungen und Zuweisungen werden in der Reihenfolge ausgeführt, in der die Ausdrücke in den Arrayinitialisierer geschrieben werden – mit anderen Worten, Elemente werden in steigender Index Reihenfolge initialisiert, wobei die äußerste Rechte Dimension zuerst zunimmt.The evaluations and assignments are performed in the order the expressions are written in the array initializer—in other words, elements are initialized in increasing index order, with the rightmost dimension increasing first. Wenn die Auswertung eines angegebenen Ausdrucks oder der nachfolgenden Zuweisung zum entsprechenden Array Element eine Ausnahme auslöst, werden keine weiteren Elemente initialisiert (und die restlichen Elemente haben daher ihre Standardwerte).If evaluation of a given expression or the subsequent assignment to the corresponding array element causes an exception, then no further elements are initialized (and the remaining elements will thus have their default values).

Ein Array Erstellungs Ausdruck ermöglicht die Instanziierung eines Arrays mit Elementen eines Arraytyps, aber die Elemente eines solchen Arrays müssen manuell initialisiert werden.An array creation expression permits instantiation of an array with elements of an array type, but the elements of such an array must be manually initialized. Beispielsweise ist die-AnweisungFor example, the statement

int[][] a = new int[100][];

erstellt ein eindimensionales Array mit 100 Elementen vom Typ int[] .creates a single-dimensional array with 100 elements of type int[]. Der Anfangswert jedes Elements ist null .The initial value of each element is null. Es ist nicht möglich, dass derselbe Array Erstellungs Ausdruck auch die Unterarrays und die-Anweisung instanziiert.It is not possible for the same array creation expression to also instantiate the sub-arrays, and the statement

int[][] a = new int[100][5];        // Error

führt zu einem Kompilierzeitfehler.results in a compile-time error. Die Instanziierung der Unterarrays muss stattdessen manuell ausgeführt werden, wie inInstantiation of the sub-arrays must instead be performed manually, as in

int[][] a = new int[100][];
for (int i = 0; i < 100; i++) a[i] = new int[5];

Wenn ein Array von Arrays eine "rechteckige" Form hat, d. h., wenn die Teil Arrays die gleiche Länge haben, ist es effizienter, ein mehrdimensionales Array zu verwenden.When an array of arrays has a "rectangular" shape, that is when the sub-arrays are all of the same length, it is more efficient to use a multi-dimensional array. Im obigen Beispiel erstellt die Instanziierung des Arrays von Arrays 101 Objekte – ein äußeres Array und 100 Teil Arrays.In the example above, instantiation of the array of arrays creates 101 objects—one outer array and 100 sub-arrays. Im Gegensatz dazuIn contrast,

int[,] = new int[100, 5];

erstellt nur ein einzelnes-Objekt, ein zweidimensionales Array und erreicht die Zuordnung in einer einzelnen Anweisung.creates only a single object, a two-dimensional array, and accomplishes the allocation in a single statement.

Im folgenden finden Sie Beispiele für implizit typisierte Array Erstellungs Ausdrücke:The following are examples of implicitly typed array creation expressions:

var a = new[] { 1, 10, 100, 1000 };                       // int[]

var b = new[] { 1, 1.5, 2, 2.5 };                         // double[]

var c = new[,] { { "hello", null }, { "world", "!" } };   // string[,]

var d = new[] { 1, "one", 2, "two" };                     // Error

Der letzte Ausdruck verursacht einen Kompilierzeitfehler, weil weder int noch string implizit in den anderen konvertiert werden kann, sodass es keinen optimalen allgemeinen Typ gibt.The last expression causes a compile-time error because neither int nor string is implicitly convertible to the other, and so there is no best common type. In diesem Fall muss ein explizit typisierter Array Erstellungs Ausdruck verwendet werden, z. b. die Angabe des Typs object[] .An explicitly typed array creation expression must be used in this case, for example specifying the type to be object[]. Alternativ kann eines der Elemente in einen allgemeinen Basistyp umgewandelt werden, der dann zum abzurufenden Elementtyp wird.Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.

Implizit typisierte Array Erstellungs Ausdrücke können mit anonymen Objektinitialisierern (anonymen Objekt Erstellungs Ausdrücken) kombiniert werden, um anonym typisierte Datenstrukturen zu erstellen.Implicitly typed array creation expressions can be combined with anonymous object initializers (Anonymous object creation expressions) to create anonymously typed data structures. Beispiel:For example:

var contacts = new[] {
    new {
        Name = "Chris Smith",
        PhoneNumbers = new[] { "206-555-0101", "425-882-8080" }
    },
    new {
        Name = "Bob Harris",
        PhoneNumbers = new[] { "650-555-0199" }
    }
};

Delegatenerstellungs AusdrückeDelegate creation expressions

Eine delegate_creation_expression wird zum Erstellen einer neuen Instanz einer delegate_type verwendet.A delegate_creation_expression is used to create a new instance of a delegate_type.

delegate_creation_expression
    : 'new' delegate_type '(' expression ')'
    ;

Das Argument eines delegaterstellungs-Ausdrucks muss eine Methoden Gruppe, eine anonyme Funktion oder ein Wert entweder der Kompilier Zeittyp dynamic oder ein delegate_type sein.The argument of a delegate creation expression must be a method group, an anonymous function or a value of either the compile time type dynamic or a delegate_type. Wenn das Argument eine Methoden Gruppe ist, identifiziert es die-Methode und für eine Instanzmethode das-Objekt, für das ein Delegat erstellt werden soll.If the argument is a method group, it identifies the method and, for an instance method, the object for which to create a delegate. Wenn das Argument eine anonyme Funktion ist, werden die Parameter und der Methoden Text des delegatziels direkt definiert.If the argument is an anonymous function it directly defines the parameters and method body of the delegate target. Wenn das-Argument ein Wert ist, wird eine Delegatinstanz identifiziert, von der eine Kopie erstellt werden soll.If the argument is a value it identifies a delegate instance of which to create a copy.

Wenn der Ausdruck den Kompilier Zeittyp aufweist dynamic , wird der delegate_creation_expression dynamisch gebunden (dynamische Bindung), und die unten aufgeführten Regeln werden zur Laufzeit mit dem Lauf Zeittyp des Ausdrucks angewendet.If the expression has the compile-time type dynamic, the delegate_creation_expression is dynamically bound (Dynamic binding), and the rules below are applied at run-time using the run-time type of the expression. Andernfalls werden die Regeln zur Kompilierzeit angewendet.Otherwise the rules are applied at compile-time.

Die Bindungs Zeit Verarbeitung einer delegate_creation_expression der Form new D(E) , wobei D ein delegate_type und E ein Ausdruck ist, besteht aus den folgenden Schritten:The binding-time processing of a delegate_creation_expression of the form new D(E), where D is a delegate_type and E is an expression, consists of the following steps:

  • Wenn E eine Methoden Gruppe ist, wird der delegaterstellungs-Ausdruck auf die gleiche Weise wie eine Methoden Gruppen Konvertierung (Methoden Gruppen Konvertierungen) von E in verarbeitet D .If E is a method group, the delegate creation expression is processed in the same way as a method group conversion (Method group conversions) from E to D.
  • Wenn E eine anonyme Funktion ist, wird der delegaterstellungs-Ausdruck auf die gleiche Weise wie eine anonyme Funktions Konvertierung (Anonyme Funktions Konvertierungen) von E in verarbeitet D .If E is an anonymous function, the delegate creation expression is processed in the same way as an anonymous function conversion (Anonymous function conversions) from E to D.
  • Wenn E ein-Wert ist, E muss kompatibel (Delegatdeklarationen) mit sein D , und das Ergebnis ist ein Verweis auf einen neu erstellten Delegaten vom Typ, der D auf dieselbe Aufruf Liste wie verweist E .If E is a value, E must be compatible (Delegate declarations) with D, and the result is a reference to a newly created delegate of type D that refers to the same invocation list as E. Wenn E nicht mit kompatibel ist D , tritt ein Kompilierzeitfehler auf.If E is not compatible with D, a compile-time error occurs.

Die Lauf Zeit Verarbeitung einer delegate_creation_expression der Form new D(E) , wobei D ein delegate_type und E ein Ausdruck ist, besteht aus den folgenden Schritten:The run-time processing of a delegate_creation_expression of the form new D(E), where D is a delegate_type and E is an expression, consists of the following steps:

  • Wenn E eine Methoden Gruppe ist, wird der delegaterstellungs-Ausdruck als Methoden Gruppen Konvertierung (Methoden Gruppen Konvertierungen) von E in ausgewertet D .If E is a method group, the delegate creation expression is evaluated as a method group conversion (Method group conversions) from E to D.
  • Wenn E eine anonyme Funktion ist, wird die Delegaterstellung als anonyme Funktions Konvertierung von E in ausgewertet D (Anonyme Funktions Konvertierungen).If E is an anonymous function, the delegate creation is evaluated as an anonymous function conversion from E to D (Anonymous function conversions).
  • Wenn E ein Wert eines delegate_type ist:If E is a value of a delegate_type:
    • E wird ausgewertet.E is evaluated. Wenn diese Auswertung eine Ausnahme verursacht, werden keine weiteren Schritte ausgeführt.If this evaluation causes an exception, no further steps are executed.
    • Wenn der Wert von E ist null , wird eine ausgelöst, System.NullReferenceException und es werden keine weiteren Schritte ausgeführt.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Eine neue Instanz des Delegattyps D wird zugewiesen.A new instance of the delegate type D is allocated. Wenn nicht genügend Arbeitsspeicher zur Verfügung steht, um die neue Instanz zuzuordnen, wird eine ausgelöst, System.OutOfMemoryException und es werden keine weiteren Schritte ausgeführt.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • Die neue Delegatinstanz wird mit der gleichen Aufruf Liste initialisiert wie die Delegatinstanz, die von angegeben wird E .The new delegate instance is initialized with the same invocation list as the delegate instance given by E.

Die Aufruf Liste eines Delegaten wird bestimmt, wenn der Delegat instanziiert wird, und wird dann für die gesamte Lebensdauer des Delegaten konstant bleiben.The invocation list of a delegate is determined when the delegate is instantiated and then remains constant for the entire lifetime of the delegate. Anders ausgedrückt: Es ist nicht möglich, die Ziel Aufruf baren Entitäten eines Delegaten zu ändern, nachdem er erstellt wurde.In other words, it is not possible to change the target callable entities of a delegate once it has been created. Wenn zwei Delegaten kombiniert werden oder eine aus einer anderen entfernt wird (Delegatdeklarationen), ergibt sich ein neuer Delegat. der Inhalt eines vorhandenen Delegaten wurde nicht geändert.When two delegates are combined or one is removed from another (Delegate declarations), a new delegate results; no existing delegate has its contents changed.

Es ist nicht möglich, einen Delegaten zu erstellen, der auf eine Eigenschaft, einen Indexer, einen benutzerdefinierten Operator, einen Instanzkonstruktor, einen Dekonstruktor oder einen statischen Konstruktor verweist.It is not possible to create a delegate that refers to a property, indexer, user-defined operator, instance constructor, destructor, or static constructor.

Wie oben beschrieben, wird beim Erstellen eines Delegaten aus einer Methoden Gruppe die Liste der formalen Parameter und der Rückgabetyp des Delegaten bestimmt, welche der überladenen Methoden ausgewählt werden sollen.As described above, when a delegate is created from a method group, the formal parameter list and return type of the delegate determine which of the overloaded methods to select. Im BeispielIn the example

delegate double DoubleFunc(double x);

class A
{
    DoubleFunc f = new DoubleFunc(Square);

    static float Square(float x) {
        return x * x;
    }

    static double Square(double x) {
        return x * x;
    }
}

Das- A.f Feld wird mit einem Delegaten initialisiert, der sich auf die zweite Methode bezieht, Square da diese Methode exakt mit der formalen Parameterliste und dem Rückgabetyp von übereinstimmt DoubleFunc .the A.f field is initialized with a delegate that refers to the second Square method because that method exactly matches the formal parameter list and return type of DoubleFunc. Wenn die zweite Square Methode nicht vorhanden wäre, wäre ein Kompilierzeitfehler aufgetreten.Had the second Square method not been present, a compile-time error would have occurred.

Ausdrücke zum Erstellen anonymer ObjekteAnonymous object creation expressions

Ein anonymous_object_creation_expression wird zum Erstellen eines Objekts eines anonymen Typs verwendet.An anonymous_object_creation_expression is used to create an object of an anonymous type.

anonymous_object_creation_expression
    : 'new' anonymous_object_initializer
    ;

anonymous_object_initializer
    : '{' member_declarator_list? '}'
    | '{' member_declarator_list ',' '}'
    ;

member_declarator_list
    : member_declarator (',' member_declarator)*
    ;

member_declarator
    : simple_name
    | member_access
    | base_access
    | null_conditional_member_access
    | identifier '=' expression
    ;

Ein Anonymer Objektinitialisierer deklariert einen anonymen Typ und gibt eine Instanz dieses Typs zurück.An anonymous object initializer declares an anonymous type and returns an instance of that type. Ein anonymer Typ ist ein namenloser Klassentyp, der direkt von erbt object .An anonymous type is a nameless class type that inherits directly from object. Die Member eines anonymen Typs sind eine Sequenz von schreibgeschützten Eigenschaften, die vom anonymen Objektinitialisierer abgeleitet werden, um eine Instanz des Typs zu erstellen.The members of an anonymous type are a sequence of read-only properties inferred from the anonymous object initializer used to create an instance of the type. Genauer gesagt: ein Anonymer Objektinitialisierer des FormularsSpecifically, an anonymous object initializer of the form

new { p1 = e1, p2 = e2, ..., pn = en }

deklariert einen anonymen Typ des Formulars.declares an anonymous type of the form

class __Anonymous1
{
    private readonly T1 f1;
    private readonly T2 f2;
    ...
    private readonly Tn fn;

    public __Anonymous1(T1 a1, T2 a2, ..., Tn an) {
        f1 = a1;
        f2 = a2;
        ...
        fn = an;
    }

    public T1 p1 { get { return f1; } }
    public T2 p2 { get { return f2; } }
    ...
    public Tn pn { get { return fn; } }

    public override bool Equals(object __o) { ... }
    public override int GetHashCode() { ... }
}

wobei jede Tx der Typen des entsprechenden Ausdrucks ist ex .where each Tx is the type of the corresponding expression ex. Der Ausdruck, der in einem member_declarator verwendet wird, muss einen Typ aufweisen.The expression used in a member_declarator must have a type. Daher ist es ein Kompilierzeitfehler für einen Ausdruck in einer member_declarator NULL oder eine anonyme Funktion zu sein.Thus, it is a compile-time error for an expression in a member_declarator to be null or an anonymous function. Es ist auch ein Kompilierzeitfehler, wenn der Ausdruck einen unsicheren Typ hat.It is also a compile-time error for the expression to have an unsafe type.

Die Namen eines anonymen Typs und des-Parameters für die zugehörige- Equals Methode werden vom Compiler automatisch generiert, und im Programmtext kann nicht auf Sie verwiesen werden.The names of an anonymous type and of the parameter to its Equals method are automatically generated by the compiler and cannot be referenced in program text.

Innerhalb desselben Programms werden zwei anonyme Objektinitialisierer, die eine Sequenz von Eigenschaften mit denselben Namen und Kompilierzeit Typen in derselben Reihenfolge angeben, Instanzen desselben anonymen Typs erstellen.Within the same program, two anonymous object initializers that specify a sequence of properties of the same names and compile-time types in the same order will produce instances of the same anonymous type.

Im BeispielIn the example

var p1 = new { Name = "Lawnmower", Price = 495.00 };
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2;

die Zuweisung in der letzten Zeile ist zulässig, da p1 und p2 denselben anonymen Typ haben.the assignment on the last line is permitted because p1 and p2 are of the same anonymous type.

Die Equals -Methode und die- GetHashcode Methode für anonyme Typen überschreiben die von geerbten Methoden object und werden im Hinblick auf die Equals und GetHashcode der Eigenschaften definiert, sodass zwei Instanzen desselben anonymen Typs nur dann gleich sind, wenn alle Eigenschaften gleich sind.The Equals and GetHashcode methods on anonymous types override the methods inherited from object, and are defined in terms of the Equals and GetHashcode of the properties, so that two instances of the same anonymous type are equal if and only if all their properties are equal.

Ein Element Deklarator kann mit einem einfachen Namen (Typrückschluss), einem Element Zugriff (Kompilierzeit Überprüfung der dynamischen Überladungs Auflösung), einem Basis Zugriff (Basis Zugriff) oder einem NULL bedingten Member-Zugriff (null bedingte Ausdrücke als Projektions Initialisierer) abgekürzt werden.A member declarator can be abbreviated to a simple name (Type inference), a member access (Compile-time checking of dynamic overload resolution), a base access (Base access) or a null-conditional member access (Null-conditional expressions as projection initializers). Dies wird als Projektions Initialisierer bezeichnet und ist eine Abkürzung für eine Deklaration von und die Zuweisung zu einer Eigenschaft mit demselben Namen.This is called a projection initializer and is shorthand for a declaration of and assignment to a property with the same name. Insbesondere Member-Deklaratoren der FormulareSpecifically, member declarators of the forms

identifier
expr.identifier

entsprechen genau den folgenden:are precisely equivalent to the following, respectively:

identifier = identifier
identifier = expr.identifier

Folglich wählt der Bezeichner in einem Projektions Initialisierer sowohl den Wert als auch das Feld oder die Eigenschaft aus, dem der Wert zugewiesen wird.Thus, in a projection initializer the identifier selects both the value and the field or property to which the value is assigned. Intuitiv projiziert ein Projektions Initialisierer nicht nur einen Wert, sondern auch den Namen des Werts.Intuitively, a projection initializer projects not just a value, but also the name of the value.

Der typeof-OperatorThe typeof operator

Der- typeof Operator wird zum Abrufen des- System.Type Objekts für einen Typ verwendet.The typeof operator is used to obtain the System.Type object for a type.

typeof_expression
    : 'typeof' '(' type ')'
    | 'typeof' '(' unbound_type_name ')'
    | 'typeof' '(' 'void' ')'
    ;

unbound_type_name
    : identifier generic_dimension_specifier?
    | identifier '::' identifier generic_dimension_specifier?
    | unbound_type_name '.' identifier generic_dimension_specifier?
    ;

generic_dimension_specifier
    : '<' comma* '>'
    ;

comma
    : ','
    ;

Die erste Form typeof_expression besteht aus einem typeof Schlüsselwort, gefolgt von einem Typ in Klammern.The first form of typeof_expression consists of a typeof keyword followed by a parenthesized type. Das Ergebnis eines Ausdrucks dieses Formulars ist das- System.Type Objekt für den jeweiligen Typ.The result of an expression of this form is the System.Type object for the indicated type. Es ist nur ein- System.Type Objekt für einen bestimmten Typ vorhanden.There is only one System.Type object for any given type. Dies bedeutet, dass für einen  T Typ typeof(T) == typeof(T) immer true ist.This means that for a type T, typeof(T) == typeof(T) is always true. Der Typ darf nicht sein dynamic .The type cannot be dynamic.

Die zweite Form von typeof_expression besteht aus einem typeof Schlüsselwort, gefolgt von einer unbound_type_name in Klammern.The second form of typeof_expression consists of a typeof keyword followed by a parenthesized unbound_type_name. Ein- unbound_type_name ähnelt einem TYPE_NAME (Namespace und Typnamen), mit dem Unterschied, dass ein unbound_type_name generic_dimension_specifier s enthält, in denen eine TYPE_NAME type_argument_list s enthält.An unbound_type_name is very similar to a type_name (Namespace and type names) except that an unbound_type_name contains generic_dimension_specifier s where a type_name contains type_argument_list s. Wenn der Operand einer typeof_expression eine Sequenz von Token ist, die die Grammatiken von unbound_type_name und TYPE_NAME erfüllt, d. h., wenn weder ein generic_dimension_specifier noch ein type_argument_list enthalten ist, wird die Sequenz der Token als TYPE_NAME betrachtet.When the operand of a typeof_expression is a sequence of tokens that satisfies the grammars of both unbound_type_name and type_name, namely when it contains neither a generic_dimension_specifier nor a type_argument_list, the sequence of tokens is considered to be a type_name. Die Bedeutung eines unbound_type_name wird wie folgt bestimmt:The meaning of an unbound_type_name is determined as follows:

  • Konvertieren Sie die Sequenz von Token in eine TYPE_NAME , indem Sie alle generic_dimension_specifier durch eine type_argument_list ersetzen, die dieselbe Anzahl von Kommas und das Schlüsselwort object wie jedes type_argument hat.Convert the sequence of tokens to a type_name by replacing each generic_dimension_specifier with a type_argument_list having the same number of commas and the keyword object as each type_argument.
  • Werten Sie die resultierende TYPE_NAME aus, während alle Typparameter Einschränkungen ignoriert werden.Evaluate the resulting type_name, while ignoring all type parameter constraints.
  • Der unbound_type_name wird in den ungebundenen generischen Typ aufgelöst, der dem resultierenden konstruierten Typ zugeordnet ist (gebundene und ungebundene Typen).The unbound_type_name resolves to the unbound generic type associated with the resulting constructed type (Bound and unbound types).

Das Ergebnis des typeof_expression ist das- System.Type Objekt für den resultierenden ungebundenen generischen Typ.The result of the typeof_expression is the System.Type object for the resulting unbound generic type.

Die dritte Form von typeof_expression besteht aus einem typeof Schlüsselwort, gefolgt von einem void Schlüsselwort in Klammern.The third form of typeof_expression consists of a typeof keyword followed by a parenthesized void keyword. Das Ergebnis eines Ausdrucks dieses Formulars ist das System.Type Objekt, das das Fehlen eines Typs darstellt.The result of an expression of this form is the System.Type object that represents the absence of a type. Das von zurückgegebene Typobjekt unter typeof(void) scheidet sich vom Typobjekt, das für einen beliebigen Typ zurückgegeben wurde.The type object returned by typeof(void) is distinct from the type object returned for any type. Dieses besondere Typobjekt ist nützlich in Klassenbibliotheken, die die Reflektion auf Methoden in der Sprache zulassen, wobei diese Methoden eine Möglichkeit haben möchten, den Rückgabetyp jeder Methode, einschließlich void-Methoden, mit einer Instanz von darzustellen System.Type .This special type object is useful in class libraries that allow reflection onto methods in the language, where those methods wish to have a way to represent the return type of any method, including void methods, with an instance of System.Type.

Der- typeof Operator kann für einen Typparameter verwendet werden.The typeof operator can be used on a type parameter. Das Ergebnis ist das- System.Type Objekt für den Lauf Zeittyp, der an den Typparameter gebunden wurde.The result is the System.Type object for the run-time type that was bound to the type parameter. Der typeof Operator kann auch für einen konstruierten Typ oder einen ungebundenen generischen Typ (gebundene und ungebundene Typen) verwendet werden.The typeof operator can also be used on a constructed type or an unbound generic type (Bound and unbound types). Das- System.Type Objekt für einen ungebundenen generischen Typ ist nicht mit dem- System.Type Objekt des Instanztyps identisch.The System.Type object for an unbound generic type is not the same as the System.Type object of the instance type. Der Instanztyp ist zur Laufzeit immer ein geschlossener konstruierter Typ, sodass System.Type das Objekt von den verwendeten Lauf Zeittyp Argumenten abhängt, während der ungebundene generische Typ keine Typargumente aufweist.The instance type is always a closed constructed type at run-time so its System.Type object depends on the run-time type arguments in use, while the unbound generic type has no type arguments.

Das BeispielThe example

using System;

class X<T>
{
    public static void PrintTypes() {
        Type[] t = {
            typeof(int),
            typeof(System.Int32),
            typeof(string),
            typeof(double[]),
            typeof(void),
            typeof(T),
            typeof(X<T>),
            typeof(X<X<T>>),
            typeof(X<>)
        };
        for (int i = 0; i < t.Length; i++) {
            Console.WriteLine(t[i]);
        }
    }
}

class Test
{
    static void Main() {
        X<int>.PrintTypes();
    }
}

erzeugt die folgende Ausgabe:produces the following output:

System.Int32
System.Int32
System.String
System.Double[]
System.Void
System.Int32
X`1[System.Int32]
X`1[X`1[System.Int32]]
X`1[T]

Beachten Sie, dass int und System.Int32 denselben Typ haben.Note that int and System.Int32 are the same type.

Beachten Sie auch, dass das Ergebnis von typeof(X<>) nicht vom Typargument abhängt, sondern vom Ergebnis von typeof(X<T>) .Also note that the result of typeof(X<>) does not depend on the type argument but the result of typeof(X<T>) does.

Checked- und Unchecked-OperatorenThe checked and unchecked operators

Die checked unchecked Operatoren und werden verwendet, um den Überlauf Überprüfungs Kontext für arithmetische Operationen und Konvertierungen im ganzzahligen Typ zu steuern.The checked and unchecked operators are used to control the overflow checking context for integral-type arithmetic operations and conversions.

checked_expression
    : 'checked' '(' expression ')'
    ;

unchecked_expression
    : 'unchecked' '(' expression ')'
    ;

Der checked Operator wertet den enthaltenen Ausdruck in einem überprüften Kontext aus, und der unchecked Operator wertet den enthaltenen Ausdruck in einem nicht überprüften Kontext aus.The checked operator evaluates the contained expression in a checked context, and the unchecked operator evaluates the contained expression in an unchecked context. Ein checked_expression oder unchecked_expression entspricht genau einem parenthesized_expression (in Klammern Klammern), mit dem Unterschied, dass der enthaltene Ausdruck im angegebenen Überlauf Prüfungs Kontext ausgewertet wird.A checked_expression or unchecked_expression corresponds exactly to a parenthesized_expression (Parenthesized expressions), except that the contained expression is evaluated in the given overflow checking context.

Der Überlauf Überprüfungs Kontext kann auch durch die checked -und- unchecked Anweisungen (dieaktivierten und deaktivierten Anweisungen) gesteuert werden.The overflow checking context can also be controlled through the checked and unchecked statements (The checked and unchecked statements).

Die folgenden Vorgänge wirken sich auf den Überlauf Prüfungs Kontext aus, der von den checked unchecked Operatoren und und-Anweisungen festgelegt wird:The following operations are affected by the overflow checking context established by the checked and unchecked operators and statements:

Wenn eine der obigen Vorgänge ein Ergebnis erzeugt, das zu groß für die Darstellung im Zieltyp ist, steuert der Kontext, in dem der Vorgang ausgeführt wird, das resultierende Verhalten:When one of the above operations produce a result that is too large to represent in the destination type, the context in which the operation is performed controls the resulting behavior:

  • In einem checked Kontext tritt ein Kompilierzeitfehler auf, wenn es sich bei dem Vorgang um einen konstanten Ausdruck (Konstante Ausdrücke) handelt.In a checked context, if the operation is a constant expression (Constant expressions), a compile-time error occurs. Andernfalls wird eine ausgelöst, wenn der Vorgang zur Laufzeit ausgeführt wird System.OverflowException .Otherwise, when the operation is performed at run-time, a System.OverflowException is thrown.
  • In einem unchecked Kontext wird das Ergebnis abgeschnitten, indem alle höherwertigen Bits verworfen werden, die nicht in den Zieltyp passen.In an unchecked context, the result is truncated by discarding any high-order bits that do not fit in the destination type.

Für nicht konstante Ausdrücke (Ausdrücke, die zur Laufzeit ausgewertet werden), die nicht von einem checked or- unchecked Operator oder-Anweisungen eingeschlossen sind, ist der Standardkontext der Überlauf Überprüfung, unchecked es sei denn, externe Faktoren (z. b. compilerswitches und Konfiguration der Ausführungsumgebung) werden zur checked Auswertung aufgerufen.For non-constant expressions (expressions that are evaluated at run-time) that are not enclosed by any checked or unchecked operators or statements, the default overflow checking context is unchecked unless external factors (such as compiler switches and execution environment configuration) call for checked evaluation.

Für konstante Ausdrücke (Ausdrücke, die zur Kompilierzeit vollständig ausgewertet werden können) ist der Standardkontext der Überlauf Überprüfung immer checked .For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. Wenn ein konstanter Ausdruck nicht explizit in einem Kontext abgelegt wird unchecked , verursachen über Flüsse, die während der Kompilierzeit Auswertung des Ausdrucks auftreten, immer Kompilierzeitfehler.Unless a constant expression is explicitly placed in an unchecked context, overflows that occur during the compile-time evaluation of the expression always cause compile-time errors.

Der Text einer anonymen Funktion ist nicht von- checked oder- unchecked Kontexten betroffen, in denen die anonyme Funktion auftritt.The body of an anonymous function is not affected by checked or unchecked contexts in which the anonymous function occurs.

Im BeispielIn the example

class Test
{
    static readonly int x = 1000000;
    static readonly int y = 1000000;

    static int F() {
        return checked(x * y);      // Throws OverflowException
    }

    static int G() {
        return unchecked(x * y);    // Returns -727379968
    }

    static int H() {
        return x * y;               // Depends on default
    }
}

Es werden keine Kompilierzeitfehler gemeldet, da keiner der Ausdrücke zur Kompilierzeit ausgewertet werden kann.no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. Zur Laufzeit löst die F Methode eine aus System.OverflowException , und die G Methode gibt-727379968 (die unteren 32 Bits des Ergebnisses außerhalb des gültigen Bereichs) zurück.At run-time, the F method throws a System.OverflowException, and the G method returns -727379968 (the lower 32 bits of the out-of-range result). Das Verhalten der- H Methode hängt vom Standardkontext der Überlauf Überprüfung für die Kompilierung ab, ist jedoch entweder identisch mit F oder gleich G .The behavior of the H method depends on the default overflow checking context for the compilation, but it is either the same as F or the same as G.

Im BeispielIn the example

class Test
{
    const int x = 1000000;
    const int y = 1000000;

    static int F() {
        return checked(x * y);      // Compile error, overflow
    }

    static int G() {
        return unchecked(x * y);    // Returns -727379968
    }

    static int H() {
        return x * y;               // Compile error, overflow
    }
}

die Überläufe, die beim Auswerten der Konstanten Ausdrücke in auftreten F und H bewirken, dass Kompilierzeitfehler gemeldet werden, weil die Ausdrücke in einem Kontext ausgewertet werden checked .the overflows that occur when evaluating the constant expressions in F and H cause compile-time errors to be reported because the expressions are evaluated in a checked context. Ein Überlauf tritt auch auf, wenn der Konstante Ausdruck in ausgewertet wird G , aber da die Auswertung in einem Kontext stattfindet unchecked , wird der Überlauf nicht gemeldet.An overflow also occurs when evaluating the constant expression in G, but since the evaluation takes place in an unchecked context, the overflow is not reported.

Die checked unchecked Operatoren und wirken sich nur auf den Überlauf Überprüfungs Kontext für die Vorgänge aus, die in den ( Token "" und "" textuell enthalten sind ) .The checked and unchecked operators only affect the overflow checking context for those operations that are textually contained within the "(" and ")" tokens. Die Operatoren haben keine Auswirkung auf Funktionsmember, die als Ergebnis der Auswertung des enthaltenen Ausdrucks aufgerufen werden.The operators have no effect on function members that are invoked as a result of evaluating the contained expression. Im BeispielIn the example

class Test
{
    static int Multiply(int x, int y) {
        return x * y;
    }

    static int F() {
        return checked(Multiply(1000000, 1000000));
    }
}

die Verwendung von checked in F hat keine Auswirkung auf die Auswertung von x * y in Multiply , daher x * y wird im Standardkontext der Überlauf Überprüfung ausgewertet.the use of checked in F does not affect the evaluation of x * y in Multiply, so x * y is evaluated in the default overflow checking context.

Der- unchecked Operator ist praktisch, wenn Konstanten der ganzzahligen Typen mit Vorzeichen in hexadezimal Notation geschrieben werden.The unchecked operator is convenient when writing constants of the signed integral types in hexadecimal notation. Beispiel:For example:

class Test
{
    public const int AllBits = unchecked((int)0xFFFFFFFF);

    public const int HighBit = unchecked((int)0x80000000);
}

Beide hexadezimal Konstanten oben sind vom Typ uint .Both of the hexadecimal constants above are of type uint. Da die Konstanten int ohne den-Operator außerhalb des Bereichs liegen unchecked , würden die Umwandlungen in int Kompilierzeitfehler verursachen.Because the constants are outside the int range, without the unchecked operator, the casts to int would produce compile-time errors.

checkedMit den unchecked Operatoren und und Anweisungen können Programmierer bestimmte Aspekte einiger numerischer Berechnungen steuern.The checked and unchecked operators and statements allow programmers to control certain aspects of some numeric calculations. Das Verhalten einiger numerischer Operatoren hängt jedoch von den Datentypen ihrer Operanden ab.However, the behavior of some numeric operators depends on their operands' data types. Beispielsweise führt die Multiplikation von zwei Dezimalzahlen immer zu einer Ausnahme bei einem Überlauf, auch innerhalb eines expliziten unchecked Konstrukts.For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked construct. Analog dazu führt das Multiplizieren von zwei Gleit Komma zahlen niemals zu einer Ausnahme bei einem Überlauf, auch innerhalb eines expliziten checked AufbausSimilarly, multiplying two floats never results in an exception on overflow even within an explicitly checked construct. Außerdem sind andere Operatoren nie von dem Überprüfungs Modus betroffen, ob Standard oder explizit.In addition, other operators are never affected by the mode of checking, whether default or explicit.

Standardwert AusdrückeDefault value expressions

Ein Standardwert Ausdruck wird zum Abrufen des Standardwerts (Standardwerte) eines Typs verwendet.A default value expression is used to obtain the default value (Default values) of a type. In der Regel wird ein Standardwert Ausdruck für Typparameter verwendet, da möglicherweise nicht bekannt ist, ob der Typparameter ein Werttyp oder ein Verweistyp ist.Typically a default value expression is used for type parameters, since it may not be known if the type parameter is a value type or a reference type. (Es ist keine Konvertierung vom null Literaltyp zu einem Typparameter vorhanden, es sei denn, der Typparameter ist ein Referenztyp.)(No conversion exists from the null literal to a type parameter unless the type parameter is known to be a reference type.)

default_value_expression
    : 'default' '(' type ')'
    ;

Wenn der Typ in einem default_value_expression zur Laufzeit als Verweistyp ausgewertet wird, wird das Ergebnis null in diesen Typ konvertiert.If the type in a default_value_expression evaluates at run-time to a reference type, the result is null converted to that type. Wenn der Typ in einer default_value_expression zur Laufzeit auf einen Werttyp ausgewertet wird, ist das Ergebnis der Standardwert der value_type(Standardkonstruktoren).If the type in a default_value_expression evaluates at run-time to a value type, the result is the value_type's default value (Default constructors).

Ein default_value_expression ist ein konstanter Ausdruck (Konstante Ausdrücke), wenn der Typ ein Verweistyp oder ein Typparameter ist, der als Verweistyp bekannt ist (Typparameter Einschränkungen).A default_value_expression is a constant expression (Constant expressions) if the type is a reference type or a type parameter that is known to be a reference type (Type parameter constraints). Außerdem ist ein default_value_expression ein konstanter Ausdruck, wenn der Typ einem der folgenden Werttypen entspricht: sbyte , byte , short , ushort , int , uint , long , ulong , char , float , double , decimal , bool oder ein beliebiger Enumerationstyp.In addition, a default_value_expression is a constant expression if the type is one of the following value types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, or any enumeration type.

Nameof-AusdrückeNameof expressions

Ein nameof_expression wird zum Abrufen des Namens einer Programm Entität als Konstante Zeichenfolge verwendet.A nameof_expression is used to obtain the name of a program entity as a constant string.

nameof_expression
    : 'nameof' '(' named_entity ')'
    ;

named_entity
    : simple_name
    | named_entity_target '.' identifier type_argument_list?
    ;

named_entity_target
    : 'this'
    | 'base'
    | named_entity 
    | predefined_type 
    | qualified_alias_member
    ;

Der named_entity Operand ist immer ein Ausdruck.Grammatically speaking, the named_entity operand is always an expression. Da nameof kein reserviertes Schlüsselwort ist, ist ein nameof-Ausdruck immer syntaktisch mehrdeutig, wenn der einfache Name aufgerufen wird nameof .Because nameof is not a reserved keyword, a nameof expression is always syntactically ambiguous with an invocation of the simple name nameof. Aus Kompatibilitätsgründen, wenn eine Namenssuche (simple names) des namens nameof erfolgreich ist, wird der Ausdruck als invocation_expression behandelt, unabhängig davon, ob der Aufruf zulässig ist.For compatibility reasons, if a name lookup (Simple names) of the name nameof succeeds, the expression is treated as an invocation_expression -- regardless of whether the invocation is legal. Andernfalls handelt es sich um einen nameof_expression.Otherwise it is a nameof_expression.

Die Bedeutung des named_entity eines nameof_expression ist die Bedeutung des Ausdrucks als Ausdruck. Das heißt, entweder als Simple_name, als base_access oder als member_access.The meaning of the named_entity of a nameof_expression is the meaning of it as an expression; that is, either as a simple_name, a base_access or a member_access. Wenn die in einfachen Namen und dem Element Zugriff beschriebene Suche jedoch zu einem Fehler führt, weil ein Instanzmember in einem statischen Kontext gefunden wurde, erzeugt eine nameof_expression keinen derartigen Fehler.However, where the lookup described in Simple names and Member access results in an error because an instance member was found in a static context, a nameof_expression produces no such error.

Es handelt sich um einen Kompilierzeitfehler für eine named_entity die eine Methoden Gruppe für eine type_argument_list festlegt.It is a compile-time error for a named_entity designating a method group to have a type_argument_list. Es handelt sich um einen Kompilierzeitfehler für eine named_entity_target , die über den-Typ verfügen dynamic .It is a compile time error for a named_entity_target to have the type dynamic.

Bei einem nameof_expression handelt es sich um einen konstanten Ausdruck vom Typ string , der zur Laufzeit keine Auswirkung hat.A nameof_expression is a constant expression of type string, and has no effect at runtime. Insbesondere wird der named_entity nicht ausgewertet, und wird für die konkrete Zuweisungs Analyse ignoriert (Allgemeine Regeln für einfache Ausdrücke).Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). Der Wert ist der letzte Bezeichner des named_entity vor der optionalen abschließenden type_argument_list, wie folgt transformiert:Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed in the following way:

  • Wenn Sie verwendet wird, wird das Präfix " @ " entfernt.The prefix "@", if used, is removed.
  • Jede unicode_escape_sequence wird in das entsprechende Unicode-Zeichen transformiert.Each unicode_escape_sequence is transformed into its corresponding Unicode character.
  • Alle formatting_characters werden entfernt.Any formatting_characters are removed.

Dabei handelt es sich um dieselben Transformationen, die beim Testen der Gleichheit zwischen bezeichlern in Bezeichner angewendet werden.These are the same transformations applied in Identifiers when testing equality between identifiers.

TODO: BeispieleTODO: examples

Anonyme Methoden AusdrückeAnonymous method expressions

Eine anonymous_method_expression ist eine von zwei Möglichkeiten, eine anonyme Funktion zu definieren.An anonymous_method_expression is one of two ways of defining an anonymous function. Diese werden in Anonyme Funktions Ausdrückeweiter unten beschrieben.These are further described in Anonymous function expressions.

Unäre OperatorenUnary operators

Die ? + - Operatoren,,, ! , ~ , ++ ,, -- Cast und await werden als unäre Operatoren bezeichnet.The ?, +, -, !, ~, ++, --, cast, and await operators are called the unary operators.

unary_expression
    : primary_expression
    | null_conditional_expression
    | '+' unary_expression
    | '-' unary_expression
    | '!' unary_expression
    | '~' unary_expression
    | pre_increment_expression
    | pre_decrement_expression
    | cast_expression
    | await_expression
    | unary_expression_unsafe
    ;

Wenn der Operand einer unary_expression den Kompilier Zeittyp aufweist dynamic , wird er dynamisch gebunden (dynamische Bindung).If the operand of a unary_expression has the compile-time type dynamic, it is dynamically bound (Dynamic binding). In diesem Fall ist der Kompilier Zeittyp der unary_expression dynamic , und die unten beschriebene Auflösung erfolgt zur Laufzeit mit dem Lauf Zeittyp des Operanden.In this case the compile-time type of the unary_expression is dynamic, and the resolution described below will take place at run-time using the run-time type of the operand.

NULL-bedingter OperatorNull-conditional operator

Der NULL bedingte Operator wendet eine Liste von Vorgängen auf seinen Operanden nur an, wenn dieser Operand nicht NULL ist.The null-conditional operator applies a list of operations to its operand only if that operand is non-null. Andernfalls ist das Ergebnis der Anwendung des-Operators null .Otherwise the result of applying the operator is null.

null_conditional_expression
    : primary_expression null_conditional_operations
    ;

null_conditional_operations
    : null_conditional_operations? '?' '.' identifier type_argument_list?
    | null_conditional_operations? '?' '[' argument_list ']'
    | null_conditional_operations '.' identifier type_argument_list?
    | null_conditional_operations '[' argument_list ']'
    | null_conditional_operations '(' argument_list? ')'
    ;

Die Liste der Vorgänge kann Member-und Element Zugriffs Vorgänge (die selbst bedingt NULL sein können) sowie Aufrufe einschließen.The list of operations can include member access and element access operations (which may themselves be null-conditional), as well as invocation.

Der Ausdruck ist z. b. a.b?[0]?.c() ein null_conditional_expression mit einem primary_expression a.b und null_conditional_operations ?[0] (null bedingter Element Zugriff), ?.c (null bedingter Member-Zugriff) und () (Aufruf).For example, the expression a.b?[0]?.c() is a null_conditional_expression with a primary_expression a.b and null_conditional_operations ?[0] (null-conditional element access), ?.c (null-conditional member access) and () (invocation).

Bei einer null_conditional_expression E mit einem primary_expression P ist E0 der Ausdruck, der durch textuelles Entfernen der führenden ? aus den einzelnen null_conditional_operations von abgerufen wird E .For a null_conditional_expression E with a primary_expression P, let E0 be the expression obtained by textually removing the leading ? from each of the null_conditional_operations of E that have one. Konzeptionell E0 ist der Ausdruck, der ausgewertet wird, wenn keine der Null-Überprüfungen, die von den s dargestellt werden, ? eine findet null .Conceptually, E0 is the expression that will be evaluated if none of the null checks represented by the ?s do find a null.

Außerdem soll E1 der Ausdruck abgerufen werden, der durch textuelles Entfernen der führenden ? aus nur der ersten des null_conditional_operations in abgerufen wird E .Also, let E1 be the expression obtained by textually removing the leading ? from just the first of the null_conditional_operations in E. Dies kann zu einem primären Ausdruck (sofern es nur einen gibt ? ) oder zu einem anderen null_conditional_expression führen.This may lead to a primary-expression (if there was just one ?) or to another null_conditional_expression.

Wenn z. b. E der Ausdruck ist a.b?[0]?.c() , dann E0 ist der Ausdruck, a.b[0].c() und E1 ist der Ausdruck a.b[0]?.c() .For example, if E is the expression a.b?[0]?.c(), then E0 is the expression a.b[0].c() and E1 is the expression a.b[0]?.c().

Wenn E0 als "Nothing" klassifiziert wird, E wird als "Nothing" klassifiziert.If E0 is classified as nothing, then E is classified as nothing. Andernfalls wird E als Wert klassifiziert.Otherwise E is classified as a value.

E0 und E1 werden verwendet, um die Bedeutung von zu bestimmen E :E0 and E1 are used to determine the meaning of E:

  • Wenn E als statement_expression wird, ist die Bedeutung von mit der- E Anweisung identisch.If E occurs as a statement_expression the meaning of E is the same as the statement

    if ((object)P != null) E1;
    

    mit der Ausnahme, dass P nur einmal ausgewertet wird.except that P is evaluated only once.

  • Andernfalls, wenn E0 als "Nothing" klassifiziert wird, tritt ein Kompilierzeitfehler auf.Otherwise, if E0 is classified as nothing a compile-time error occurs.

  • Andernfalls ist T0 der Typ von E0 .Otherwise, let T0 be the type of E0.

    • Wenn ein T0 Typparameter ist, der nicht bekannt ist, dass es sich um einen Verweistyp oder einen nicht auf NULL festleg baren Werttyp handelt, tritt ein Kompilierzeitfehler auf.If T0 is a type parameter that is not known to be a reference type or a non-nullable value type, a compile-time error occurs.

    • Wenn T0 ein Werttyp ist, der keine NULL-Werte zulässt, ist der Typ von E T0? , und die Bedeutung von E entspricht.If T0 is a non-nullable value type, then the type of E is T0?, and the meaning of E is the same as

      ((object)P == null) ? (T0?)null : E1
      

      mit der Ausnahme, dass P nur einmal ausgewertet wird.except that P is evaluated only once.

    • Andernfalls ist der Typ von e t0, und die Bedeutung von e ist identisch mit.Otherwise the type of E is T0, and the meaning of E is the same as

      ((object)P == null) ? null : E1
      

      mit der Ausnahme, dass P nur einmal ausgewertet wird.except that P is evaluated only once.

Wenn E1 selbst ein null_conditional_expression ist, werden diese Regeln erneut angewendet, und die Tests werden null geschachtelt, bis keine weiteren vorhanden sind ? , und der Ausdruck wurde bis zum primären Ausdruck reduziert E0 .If E1 is itself a null_conditional_expression, then these rules are applied again, nesting the tests for null until there are no further ?'s, and the expression has been reduced all the way down to the primary-expression E0.

Wenn der Ausdruck beispielsweise a.b?[0]?.c() als Anweisungs Ausdruck auftritt, wie in der-Anweisung:For example, if the expression a.b?[0]?.c() occurs as a statement-expression, as in the statement:

a.b?[0]?.c();

seine Bedeutung ist äquivalent zu:its meaning is equivalent to:

if (a.b != null) a.b[0]?.c();

Das wiederum entspricht:which again is equivalent to:

if (a.b != null) if (a.b[0] != null) a.b[0].c();

Mit Ausnahme von a.b und a.b[0] werden nur einmal ausgewertet.Except that a.b and a.b[0] are evaluated only once.

Wenn Sie in einem Kontext auftritt, in dem ihr Wert verwendet wird, wie in:If it occurs in a context where its value is used, as in:

var x = a.b?[0]?.c();

und vorausgesetzt, dass der Typ des letzten aufzurufenden aufzurufenden nicht auf NULL festleg baren Werttypen ist, entspricht seine Bedeutung folgenden Werten:and assuming that the type of the final invocation is not a non-nullable value type, its meaning is equivalent to:

var x = (a.b == null) ? null : (a.b[0] == null) ? null : a.b[0].c();

mit Ausnahme von a.b und a.b[0] werden nur einmal ausgewertet.except that a.b and a.b[0] are evaluated only once.

NULL bedingte Ausdrücke als Projektions InitialisiererNull-conditional expressions as projection initializers

Ein NULL bedingter Ausdruck ist nur als member_declarator in einer anonymous_object_creation_expression zulässig (Ausdrücke zum Erstellen anonymer Objekte), wenn er mit einem (optional NULL bedingten) Member-Zugriff endet.A null-conditional expression is only allowed as a member_declarator in an anonymous_object_creation_expression (Anonymous object creation expressions) if it ends with an (optionally null-conditional) member access. Diese Anforderung kann wie folgt ausgedrückt werden:Grammatically, this requirement can be expressed as:

null_conditional_member_access
    : primary_expression null_conditional_operations? '?' '.' identifier type_argument_list?
    | primary_expression null_conditional_operations '.' identifier type_argument_list?
    ;

Dies ist ein Sonderfall der Grammatik für null_conditional_expression oben.This is a special case of the grammar for null_conditional_expression above. Die Produktion für member_declarator in Ausdrücken der anonymen Objekt Erstellung enthält dann nur null_conditional_member_access.The production for member_declarator in Anonymous object creation expressions then includes only null_conditional_member_access.

NULL bedingte Ausdrücke als Anweisungs AusdrückeNull-conditional expressions as statement expressions

Ein NULL bedingter Ausdruck ist nur als statement_expression (Ausdrucks Anweisungen) zulässig, wenn er mit einem Aufruf endet.A null-conditional expression is only allowed as a statement_expression (Expression statements) if it ends with an invocation. Diese Anforderung kann wie folgt ausgedrückt werden:Grammatically, this requirement can be expressed as:

null_conditional_invocation_expression
    : primary_expression null_conditional_operations '(' argument_list? ')'
    ;

Dies ist ein Sonderfall der Grammatik für null_conditional_expression oben.This is a special case of the grammar for null_conditional_expression above. Die Produktion für statement_expression in Ausdrucks Anweisungen enthält dann nur null_conditional_invocation_expression.The production for statement_expression in Expression statements then includes only null_conditional_invocation_expression.

Unärer Plus-OperatorUnary plus operator

Bei einem Vorgang des Formulars +x wird die Überladungs Auflösung des unären Operators (unäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form +x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Der Operand wird in den Parametertyp des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. Die vordefinierten unären plus Operatoren sind:The predefined unary plus operators are:

int operator +(int x);
uint operator +(uint x);
long operator +(long x);
ulong operator +(ulong x);
float operator +(float x);
double operator +(double x);
decimal operator +(decimal x);

Für jeden dieser Operatoren ist das Ergebnis einfach der Wert des Operanden.For each of these operators, the result is simply the value of the operand.

Unärer Minus-OperatorUnary minus operator

Bei einem Vorgang des Formulars -x wird die Überladungs Auflösung des unären Operators (unäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form -x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Der Operand wird in den Parametertyp des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. Die vordefinierten Negations Operatoren lauten wie folgt:The predefined negation operators are:

  • Ganzzahlige Negation:Integer negation:

    int operator -(int x);
    long operator -(long x);
    

    Das Ergebnis wird durch Subtrahieren x von 0 (null) berechnet.The result is computed by subtracting x from zero. Wenn der Wert von x der kleinste darstellbare Wert des Operanden Typs (-2 ^ 31 für int oder-2 ^ 63 für) ist long , kann die mathematische Negation von x nicht innerhalb des Operanden Typs darstellbar sein.If the value of x is the smallest representable value of the operand type (-2^31 for int or -2^63 for long), then the mathematical negation of x is not representable within the operand type. Wenn dies innerhalb eines checked Kontexts auftritt, wird eine ausgelöst System.OverflowException . Wenn Sie in einem unchecked Kontext auftritt, ist das Ergebnis der Wert des Operanden, und der Überlauf wird nicht gemeldet.If this occurs within a checked context, a System.OverflowException is thrown; if it occurs within an unchecked context, the result is the value of the operand and the overflow is not reported.

    Wenn der Operand des Negations Operators vom Typ ist uint , wird er in den Typ konvertiert long , und der Ergebnistyp ist long .If the operand of the negation operator is of type uint, it is converted to type long, and the type of the result is long. Eine Ausnahme ist die Regel, die zulässt, dass der int Wert-2147483648 (-2 ^ 31) als dezimales Ganzzahlliteral (ganzzahlige Literale) geschrieben wird.An exception is the rule that permits the int value -2147483648 (-2^31) to be written as a decimal integer literal (Integer literals).

    Wenn der Operand des Negations Operators vom Typ ist ulong , tritt ein Kompilierzeitfehler auf.If the operand of the negation operator is of type ulong, a compile-time error occurs. Eine Ausnahme ist die Regel, die zulässt, dass der long Wert-9.223.372.036.854.775.808 (-2 ^ 63) als dezimales Ganzzahlliteral (ganzzahlige Literale) geschrieben wird.An exception is the rule that permits the long value -9223372036854775808 (-2^63) to be written as a decimal integer literal (Integer literals).

  • Gleit Komma Negation:Floating-point negation:

    float operator -(float x);
    double operator -(double x);
    

    Das Ergebnis ist der Wert von x mit dem zugehörigen Vorzeichen.The result is the value of x with its sign inverted. Wenn x NaN ist, ist das Ergebnis ebenfalls NaN.If x is NaN, the result is also NaN.

  • Dezimale Negation:Decimal negation:

    decimal operator -(decimal x);
    

    Das Ergebnis wird durch Subtrahieren x von 0 (null) berechnet.The result is computed by subtracting x from zero. Die Dezimale Negation entspricht der Verwendung des unären Minus Operators vom Typ System.Decimal .Decimal negation is equivalent to using the unary minus operator of type System.Decimal.

Logischer Negationsoperator:Logical negation operator

Bei einem Vorgang des Formulars !x wird die Überladungs Auflösung des unären Operators (unäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form !x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Der Operand wird in den Parametertyp des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. Es ist nur ein vordefinierter logischer Negations Operator vorhanden:Only one predefined logical negation operator exists:

bool operator !(bool x);

Dieser Operator berechnet die logische Negation des Operanden: Wenn der Operand ist true , ist das Ergebnis false .This operator computes the logical negation of the operand: If the operand is true, the result is false. Wenn der Operand false ist, ist das Ergebnis true.If the operand is false, the result is true.

Bitweiser KomplementoperatorBitwise complement operator

Bei einem Vorgang des Formulars ~x wird die Überladungs Auflösung des unären Operators (unäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form ~x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Der Operand wird in den Parametertyp des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. Die vordefinierten bitweisen Komplement Operatoren sind:The predefined bitwise complement operators are:

int operator ~(int x);
uint operator ~(uint x);
long operator ~(long x);
ulong operator ~(ulong x);

Für jeden dieser Operatoren ist das Ergebnis des Vorgangs das bitweise Komplement von x .For each of these operators, the result of the operation is the bitwise complement of x.

Jeder Enumerationstyp E stellt implizit den folgenden bitweisen Komplement Operator bereit:Every enumeration type E implicitly provides the following bitwise complement operator:

E operator ~(E x);

Das Ergebnis der Auswertung von ~x , wobei x ein Ausdruck eines Enumerationstyps E mit einem zugrunde liegenden Typ ist U , ist identisch mit dem Auswerten von (E)(~(U)x) , mit der Ausnahme, dass die Konvertierung in E immer als if in einem Kontext ausgeführt wird (die aktivierten und deaktivierten unchecked Operatoren).The result of evaluating ~x, where x is an expression of an enumeration type E with an underlying type U, is exactly the same as evaluating (E)(~(U)x), except that the conversion to E is always performed as if in an unchecked context (The checked and unchecked operators).

Präfix-Inkrementoperator und Präfix-DekrementoperatorPrefix increment and decrement operators

pre_increment_expression
    : '++' unary_expression
    ;

pre_decrement_expression
    : '--' unary_expression
    ;

Der Operand eines Präfix Inkrement-oder dekrementvorgangs muss ein Ausdruck sein, der als Variable, Eigenschafts Zugriff oder Indexerzugriff klassifiziert ist.The operand of a prefix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Das Ergebnis des Vorgangs ist ein Wert desselben Typs wie der Operand.The result of the operation is a value of the same type as the operand.

Wenn der Operand einer Präfix Inkrement-oder Dekrementoperation eine Eigenschaft oder ein Indexer-Zugriff ist, muss die Eigenschaft oder der Indexer sowohl einen get -als auch einen- set Accessor aufweisen.If the operand of a prefix increment or decrement operation is a property or indexer access, the property or indexer must have both a get and a set accessor. Wenn dies nicht der Fall ist, tritt ein Bindungs Zeitfehler auf.If this is not the case, a binding-time error occurs.

Unäre Operator Überladungs Auflösung (unäre Operator Überladungs Auflösung) wird angewendet, um eine bestimmte Operator Implementierung auszuwählen.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. ++ -- Für die folgenden Typen sind vordefinierte-und-Operatoren vorhanden: sbyte , byte , short , ushort , int , uint , long , ulong , char , float , double , decimal und ein beliebiger Enumerationstyp.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Die vordefinierten ++ Operatoren geben den Wert zurück, der beim Hinzufügen von 1 zum Operanden erzeugt wurde, und die vordefinierten -- Operatoren geben den Wert zurück, der durch die Subtraktion von 1 vom Operanden erzeugt wird.The predefined ++ operators return the value produced by adding 1 to the operand, and the predefined -- operators return the value produced by subtracting 1 from the operand. Wenn in einem checked Kontext das Ergebnis dieser Addition oder Subtraktion außerhalb des Bereichs des Ergebnis Typs liegt und der Ergebnistyp ein ganzzahliger Typ oder Enumeration-Typ ist, System.OverflowException wird eine ausgelöst.In a checked context, if the result of this addition or subtraction is outside the range of the result type and the result type is an integral type or enum type, a System.OverflowException is thrown.

Die Lauf Zeit Verarbeitung einer Präfix Inkrement-oder Dekrementoperation des Formulars ++x oder --x besteht aus den folgenden Schritten:The run-time processing of a prefix increment or decrement operation of the form ++x or --x consists of the following steps:

  • Wenn x als Variable klassifiziert ist:If x is classified as a variable:
    • x wird ausgewertet, um die Variable zu entwickeln.x is evaluated to produce the variable.
    • Der ausgewählte Operator wird mit dem Wert von x als sein Argument aufgerufen.The selected operator is invoked with the value of x as its argument.
    • Der vom-Operator zurückgegebene Wert wird an dem Speicherort gespeichert, der durch die Auswertung von angegeben wird x .The value returned by the operator is stored in the location given by the evaluation of x.
    • Der vom Operator zurückgegebene Wert wird zum Ergebnis des Vorgangs.The value returned by the operator becomes the result of the operation.
  • Wenn x als Eigenschaft oder Indexer-Zugriff klassifiziert ist:If x is classified as a property or indexer access:
    • Der Instanzausdruck (wenn x nicht ist static ), und die Argumentliste (wenn x ein Indexer-Zugriff ist), die zugeordnet ist x , wird ausgewertet, und die Ergebnisse werden in den nachfolgenden get -und-Accessoraufrufen verwendet set .The instance expression (if x is not static) and the argument list (if x is an indexer access) associated with x are evaluated, and the results are used in the subsequent get and set accessor invocations.
    • Der- get Accessor von x wird aufgerufen.The get accessor of x is invoked.
    • Der ausgewählte Operator wird mit dem Wert aufgerufen, der vom get Accessor als Argument zurückgegeben wurde.The selected operator is invoked with the value returned by the get accessor as its argument.
    • Der- set Accessor von x wird mit dem Wert aufgerufen, der vom Operator als sein Argument zurückgegeben wurde value .The set accessor of x is invoked with the value returned by the operator as its value argument.
    • Der vom Operator zurückgegebene Wert wird zum Ergebnis des Vorgangs.The value returned by the operator becomes the result of the operation.

Die ++ -- Operatoren und unterstützen auch postfix-Notation (postfix-Inkrement-und Dekrementoperatoren).The ++ and -- operators also support postfix notation (Postfix increment and decrement operators). In der Regel ist das Ergebnis von x++ oder x-- der Wert von x vor dem Vorgang, wohingegen das Ergebnis von ++x oder --x der Wert von x nach dem Vorgang ist.Typically, the result of x++ or x-- is the value of x before the operation, whereas the result of ++x or --x is the value of x after the operation. In jedem Fall x hat nach dem Vorgang denselben Wert.In either case, x itself has the same value after the operation.

Eine- operator++ oder- operator-- Implementierung kann entweder mithilfe der Postfix-oder Präfix Notation aufgerufen werden.An operator++ or operator-- implementation can be invoked using either postfix or prefix notation. Es ist nicht möglich, separate Operator Implementierungen für die beiden Notationen zu haben.It is not possible to have separate operator implementations for the two notations.

cast-AusdrückeCast expressions

Ein cast_expression wird verwendet, um einen Ausdruck explizit in einen bestimmten Typ zu konvertieren.A cast_expression is used to explicitly convert an expression to a given type.

cast_expression
    : '(' type ')' unary_expression
    ;

Eine cast_expression des Formulars (T)E , wobei T ein- Typ und E ein- unary_expression ist, führt eine explizite Konvertierung (explizite Konvertierungen) des Werts von E in den Typ aus T .A cast_expression of the form (T)E, where T is a type and E is a unary_expression, performs an explicit conversion (Explicit conversions) of the value of E to type T. Wenn keine explizite Konvertierung von E in vorhanden T ist, tritt ein Bindungs Zeitfehler auf.If no explicit conversion exists from E to T, a binding-time error occurs. Andernfalls ist das Ergebnis der Wert, der von der expliziten Konvertierung erzeugt wird.Otherwise, the result is the value produced by the explicit conversion. Das Ergebnis wird immer als Wert klassifiziert, auch wenn E eine Variable bezeichnet.The result is always classified as a value, even if E denotes a variable.

Die Grammatik für eine cast_expression führt zu bestimmten syntaktischen Mehrdeutigkeiten.The grammar for a cast_expression leads to certain syntactic ambiguities. Der Ausdruck könnte z. b. (x)-y entweder als cast_expression (eine -y Umwandlung von in den-Typ x ) oder als additive_expression in Kombination mit einem parenthesized_expression (der den Wert berechnet) interpretiert werden x - y) .For example, the expression (x)-y could either be interpreted as a cast_expression (a cast of -y to type x) or as an additive_expression combined with a parenthesized_expression (which computes the value x - y).

Um cast_expression Mehrdeutigkeiten aufzulösen, ist die folgende Regel vorhanden: eine Sequenz von einem oder mehreren Token(Leerraum), die in Klammern eingeschlossen ist, wird nur als Anfang eines cast_expression betrachtet, wenn mindestens einer der folgenden Punkte zutrifft:To resolve cast_expression ambiguities, the following rule exists: A sequence of one or more token s (White space) enclosed in parentheses is considered the start of a cast_expression only if at least one of the following are true:

  • Die Reihenfolge der Token ist die korrekte Grammatik für einen Typ, jedoch nicht für einen Ausdruck.The sequence of tokens is correct grammar for a type, but not for an expression.
  • Die Reihenfolge der Token ist für einen Typ eine korrekte Grammatik, und das Token, das unmittelbar auf die schließenden Klammern folgt, ist das Token " ~ ", das Token " ! ", das Token " ( ", ein Bezeichner (Escapesequenzen für Unicode-Zeichen), ein Literalzeichen (Literale) oder ein beliebiges Schlüsselwort (Schlüsselwörter) außer as und is .The sequence of tokens is correct grammar for a type, and the token immediately following the closing parentheses is the token "~", the token "!", the token "(", an identifier (Unicode character escape sequences), a literal (Literals), or any keyword (Keywords) except as and is.

Der Begriff "korrekte Grammatik" oben bedeutet nur, dass die Abfolge der Token der jeweiligen grammatikerischen Produktion entsprechen muss.The term "correct grammar" above means only that the sequence of tokens must conform to the particular grammatical production. Dabei wird insbesondere nicht die tatsächliche Bedeutung von einzelnen Bezeichner berücksichtigt.It specifically does not consider the actual meaning of any constituent identifiers. Wenn z. b. x -und-Bezeichner y sind, dann x.y ist die korrekte Grammatik für einen Typ, auch wenn x.y nicht tatsächlich einen Typ bezeichnet.For example, if x and y are identifiers, then x.y is correct grammar for a type, even if x.y doesn't actually denote a type.

Aus der disambiguationrule folgt, dass, wenn und Bezeichner sind,, x y (x)y (x)(y) und (x)(-y) cast_expression s sind, aber (x)-y nicht, auch wenn x einen Typ identifiziert.From the disambiguation rule it follows that, if x and y are identifiers, (x)y, (x)(y), and (x)(-y) are cast_expression s, but (x)-y is not, even if x identifies a type. Wenn jedoch x ein Schlüsselwort ist, das einen vordefinierten Typ identifiziert (z. b. int ), werden alle vier Formulare cast_expression s (da ein solches Schlüsselwort nicht möglicherweise ein Ausdruck allein sein kann).However, if x is a keyword that identifies a predefined type (such as int), then all four forms are cast_expression s (because such a keyword could not possibly be an expression by itself).

Erwartungs AusdrückeAwait expressions

Der Erwartungs Operator wird verwendet, um die Auswertung der einschließenden Async-Funktion anzuhalten, bis der asynchrone Vorgang, der durch den Operanden dargestellt wird, abgeschlossen ist.The await operator is used to suspend evaluation of the enclosing async function until the asynchronous operation represented by the operand has completed.

await_expression
    : 'await' unary_expression
    ;

Ein- await_expression ist nur im Text einer Async-Funktion (Async-Funktionen) zulässig.An await_expression is only allowed in the body of an async function (Async functions). In der nächsten einschließenden asynchronen Funktion tritt möglicherweise keine await_expression an folgenden Stellen auf:Within the nearest enclosing async function, an await_expression may not occur in these places:

  • Innerhalb einer geschachtelten (nicht Async) anonymen FunktionInside a nested (non-async) anonymous function
  • Innerhalb des Blocks einer lock_statementInside the block of a lock_statement
  • In einem unsicheren KontextIn an unsafe context

Beachten Sie, dass ein await_expression an den meisten Stellen innerhalb eines query_expression nicht vorkommen kann, da diese syntaktisch transformiert werden, um nicht asynchrone Lambda-Ausdrücke zu verwenden.Note that an await_expression cannot occur in most places within a query_expression, because those are syntactically transformed to use non-async lambda expressions.

Innerhalb einer Async-Funktion await kann nicht als Bezeichner verwendet werden.Inside of an async function, await cannot be used as an identifier. Daher gibt es keine syntaktische Mehrdeutigkeit zwischen "Erwartung-Ausdrücke" und verschiedenen Ausdrücken mit bezeichmern.There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. Außerhalb der Async-Funktionen await fungiert als normaler Bezeichner.Outside of async functions, await acts as a normal identifier.

Der Operand eines await_expression wird als *Task _ bezeichnet.The operand of an await_expression is called the *task _. Sie stellt einen asynchronen Vorgang dar, der zum Zeitpunkt der Auswertung der _await_expression * möglicherweise nicht ausgeführt wird.It represents an asynchronous operation that may or may not be complete at the time the _await_expression* is evaluated. Der erwartete Operator besteht darin, die Ausführung der einschließenden Async-Funktion anzuhalten, bis die erwartete Aufgabe abgeschlossen ist, und dann das Ergebnis zu erhalten.The purpose of the await operator is to suspend execution of the enclosing async function until the awaited task is complete, and then obtain its outcome.

Awanutzbare AusdrückeAwaitable expressions

Die Aufgabe eines Erwartungs Ausdrucks muss erwartet werden.The task of an await expression is required to be awaitable. tWenn eine der folgenden Punkte enthält, kann ein Ausdruck ausgenutzt werden:An expression t is awaitable if one of the following holds:

  • t weist den Kompilier Zeittyp auf dynamict is of compile time type dynamic
  • t verfügt über eine barrierefreie Instanz-oder Erweiterungsmethode GetAwaiter , die ohne Parameter und ohne Typparameter aufgerufen wird, sowie über einen Rückgabetyp, A für den die folgenden Werte gelten:t has an accessible instance or extension method called GetAwaiter with no parameters and no type parameters, and a return type A for which all of the following hold:
    • A implementiert die-Schnittstelle System.Runtime.CompilerServices.INotifyCompletion (im folgenden als INotifyCompletion aus Gründen der Kürze bekannt).A implements the interface System.Runtime.CompilerServices.INotifyCompletion (hereafter known as INotifyCompletion for brevity)
    • A verfügt über eine barrierefreie, lesbare IsCompleted Instanzeigenschaft vom Typ. boolA has an accessible, readable instance property IsCompleted of type bool
    • A verfügt über eine barrierefreie Instanzmethode GetResult ohne Parameter und ohne Typparameter.A has an accessible instance method GetResult with no parameters and no type parameters

Der Zweck der- GetAwaiter Methode ist das Abrufen eines *akellner _ für die Aufgabe.The purpose of the GetAwaiter method is to obtain an *awaiter _ for the task. Der Typ A wird als _ akellnertyp* für den Erwartungs Ausdruck bezeichnet.The type A is called the _ awaiter type* for the await expression.

Mit der- IsCompleted Eigenschaft wird bestimmt, ob die Aufgabe bereits beendet ist.The purpose of the IsCompleted property is to determine if the task is already complete. Wenn dies der Fall ist, muss die Evaluierung nicht angehalten werden.If so, there is no need to suspend evaluation.

Der Zweck der- INotifyCompletion.OnCompleted Methode besteht darin, eine "Fortsetzung" für die Aufgabe zu registrieren, d. h. einen Delegaten (vom Typ System.Action ), der nach Abschluss der Aufgabe aufgerufen wird.The purpose of the INotifyCompletion.OnCompleted method is to sign up a "continuation" to the task; i.e. a delegate (of type System.Action) that will be invoked once the task is complete.

Der Zweck der- GetResult Methode besteht darin, das Ergebnis der Aufgabe zu erhalten, sobald Sie fertig ist.The purpose of the GetResult method is to obtain the outcome of the task once it is complete. Dieses Ergebnis kann erfolgreich abgeschlossen werden, möglicherweise mit einem Ergebniswert, oder es handelt sich um eine Ausnahme, die von der-Methode ausgelöst wird GetResult .This outcome may be successful completion, possibly with a result value, or it may be an exception which is thrown by the GetResult method.

Klassifizierung von Erwartungs AusdrückenClassification of await expressions

Der Ausdruck await t wird auf die gleiche Weise klassifiziert wie der Ausdruck (t).GetAwaiter().GetResult() .The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Wenn der Rückgabetyp von den Wert GetResult void hat, wird der await_expression daher als "Nothing" klassifiziert.Thus, if the return type of GetResult is void, the await_expression is classified as nothing. Wenn Sie einen nicht leeren Rückgabetyp aufweist T , wird die await_expression als Wert des Typs klassifiziert T .If it has a non-void return type T, the await_expression is classified as a value of type T.

Lauf Zeit Auswertung von Erwartungs AusdrückenRuntime evaluation of await expressions

Zur Laufzeit wird der Ausdruck await t wie folgt ausgewertet:At runtime, the expression await t is evaluated as follows:

  • Ein akellner a wird durch Auswerten des Ausdrucks abgerufen (t).GetAwaiter() .An awaiter a is obtained by evaluating the expression (t).GetAwaiter().
  • Eine bool b wird durch Auswerten des Ausdrucks abgerufen (a).IsCompleted .A bool b is obtained by evaluating the expression (a).IsCompleted.
  • Wenn b false die Auswertung von ist, hängt davon ab, ob a die-Schnittstelle implementiert System.Runtime.CompilerServices.ICriticalNotifyCompletion (im folgenden als ICriticalNotifyCompletion aus Gründen der Kürze bekannt).If b is false then evaluation depends on whether a implements the interface System.Runtime.CompilerServices.ICriticalNotifyCompletion (hereafter known as ICriticalNotifyCompletion for brevity). Diese Überprüfung erfolgt zur Bindungs Zeit. a , wenn beispielsweise zur Laufzeit, wenn den Kompilier Zeittyp dynamic und zur Kompilierzeit aufweist.This check is done at binding time; i.e. at runtime if a has the compile time type dynamic, and at compile time otherwise. rBezeichnen Sie den Wiederaufnahme Delegaten (Async-Funktionen):Let r denote the resumption delegate (Async functions):
    • Wenn a nicht implementiert ICriticalNotifyCompletion , wird der Ausdruck (a as (INotifyCompletion)).OnCompleted(r) ausgewertet.If a does not implement ICriticalNotifyCompletion, then the expression (a as (INotifyCompletion)).OnCompleted(r) is evaluated.
    • Wenn a implementiert ICriticalNotifyCompletion , wird der Ausdruck (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) ausgewertet.If a does implement ICriticalNotifyCompletion, then the expression (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) is evaluated.
    • Die Auswertung wird dann angehalten, und die Steuerung wird an den aktuellen Aufrufer der Async-Funktion zurückgegeben.Evaluation is then suspended, and control is returned to the current caller of the async function.
  • Der Ausdruck wird entweder unmittelbar nach (wenn b was true ) oder nach einem späteren Aufruf des Wiederaufnahme Delegaten (wenn b Was ist false ) (a).GetResult() ausgewertet.Either immediately after (if b was true), or upon later invocation of the resumption delegate (if b was false), the expression (a).GetResult() is evaluated. Wenn ein Wert zurückgegeben wird, ist dieser Wert das Ergebnis der await_expression.If it returns a value, that value is the result of the await_expression. Andernfalls ist das Ergebnis "Nothing".Otherwise the result is nothing.

Die Implementierung der Schnittstellen Methoden eines akellers INotifyCompletion.OnCompleted und ICriticalNotifyCompletion.UnsafeOnCompleted sollte bewirken r , dass der Delegat höchstens einmal aufgerufen wird.An awaiter's implementation of the interface methods INotifyCompletion.OnCompleted and ICriticalNotifyCompletion.UnsafeOnCompleted should cause the delegate r to be invoked at most once. Andernfalls ist das Verhalten der einschließenden Async-Funktion nicht definiert.Otherwise, the behavior of the enclosing async function is undefined.

Arithmetische operatorenArithmetic operators

Die * / % Operatoren,,, + und - werden als arithmetische Operatoren bezeichnet.The *, /, %, +, and - operators are called the arithmetic operators.

multiplicative_expression
    : unary_expression
    | multiplicative_expression '*' unary_expression
    | multiplicative_expression '/' unary_expression
    | multiplicative_expression '%' unary_expression
    ;

additive_expression
    : multiplicative_expression
    | additive_expression '+' multiplicative_expression
    | additive_expression '-' multiplicative_expression
    ;

Wenn ein Operand eines arithmetischen Operators den Kompilier Zeittyp aufweist dynamic , wird der Ausdruck dynamisch gebunden (dynamische Bindung).If an operand of an arithmetic operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In diesem Fall ist der Kompilier Zeittyp des Ausdrucks dynamic , und die unten beschriebene Auflösung erfolgt zur Laufzeit mit dem Lauf Zeittyp der Operanden, die den Kompilier Zeittyp aufweisen dynamic .In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

MultiplikationsoperatorMultiplication operator

Bei einem Vorgang des Formulars x * y wird die binäre Operator Überladungs Auflösung (binäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form x * y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Die Operanden werden in die Parametertypen des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Die vordefinierten Multiplikations Operatoren sind unten aufgeführt.The predefined multiplication operators are listed below. Alle Operatoren berechnen das Produkt von x und y .The operators all compute the product of x and y.

  • Integer-Multiplikation:Integer multiplication:

    int operator *(int x, int y);
    uint operator *(uint x, uint y);
    long operator *(long x, long y);
    ulong operator *(ulong x, ulong y);
    

    Wenn sich checked das Produkt in einem Kontext außerhalb des Bereichs des Ergebnis Typs befindet, wird eine ausgelöst System.OverflowException .In a checked context, if the product is outside the range of the result type, a System.OverflowException is thrown. In einem unchecked Kontext werden Überläufe nicht gemeldet, und alle signifikanten höherwertigen Bits außerhalb des Bereichs des Ergebnis Typs werden verworfen.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Gleit Komma Multiplikation:Floating-point multiplication:

    float operator *(float x, float y);
    double operator *(double x, double y);
    

    Das Produkt wird gemäß den Regeln der IEEE 754-Arithmetik berechnet.The product is computed according to the rules of IEEE 754 arithmetic. In der folgenden Tabelle sind die Ergebnisse für alle möglichen Kombinationen aus endlichen Werten ungleich Null, Nullen, unendlichen Werten und NaN-Werten aufgeführt.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. In der Tabelle sind x und y positive endliche Werte.In the table, x and y are positive finite values. z ist das Ergebnis von x * y.z is the result of x * y. Wenn das Ergebnis für den Zieltyp zu groß ist, ist z ein unendlicher Wert.If the result is too large for the destination type, z is infinity. Wenn das Ergebnis für den Zieltyp zu klein ist, ist z Null.If the result is too small for the destination type, z is zero.

    +y+y -y-y +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    +x+x +z+z -Z-z +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    -X-x -Z-z +z+z -0-0 +0+0 -inf-inf +inf+inf NaNNaN
    +0+0 +0+0 -0-0 +0+0 -0-0 NaNNaN NaNNaN NaNNaN
    -0-0 -0-0 +0+0 -0-0 +0+0 NaNNaN NaNNaN NaNNaN
    +inf+inf +inf+inf -inf-inf NaNNaN NaNNaN +inf+inf -inf-inf NaNNaN
    -inf-inf -inf-inf +inf+inf NaNNaN NaNNaN -inf-inf +inf+inf NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Dezimale Multiplikation:Decimal multiplication:

    decimal operator *(decimal x, decimal y);
    

    Wenn der resultierende Wert zu groß für die Darstellung im- decimal Format ist, System.OverflowException wird eine ausgelöst.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Wenn der Ergebniswert zu klein ist, um im decimal Format darzustellen, ist das Ergebnis 0 (null).If the result value is too small to represent in the decimal format, the result is zero. Die Dezimalstellen des Ergebnisses, vor der Rundung, sind die Summe der Skalen der beiden Operanden.The scale of the result, before any rounding, is the sum of the scales of the two operands.

    Die Dezimal Multiplikation entspricht der Verwendung des Multiplikations Operators vom Typ System.Decimal .Decimal multiplication is equivalent to using the multiplication operator of type System.Decimal.

DivisionsoperatorDivision operator

Bei einem Vorgang des Formulars x / y wird die binäre Operator Überladungs Auflösung (binäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form x / y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Die Operanden werden in die Parametertypen des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Die vordefinierten Divisions Operatoren sind unten aufgeführt.The predefined division operators are listed below. Die Operatoren berechnen alle den Quotienten von x und y .The operators all compute the quotient of x and y.

  • Ganzzahlige Division:Integer division:

    int operator /(int x, int y);
    uint operator /(uint x, uint y);
    long operator /(long x, long y);
    ulong operator /(ulong x, ulong y);
    

    Wenn der Wert des rechten Operanden 0 (null) ist, wird eine ausgelöst System.DivideByZeroException .If the value of the right operand is zero, a System.DivideByZeroException is thrown.

    Die Division rundet das Ergebnis auf 0 (null).The division rounds the result towards zero. Daher ist der absolute Wert des Ergebnisses die größtmögliche Ganzzahl, die kleiner oder gleich dem absoluten Wert des Quotienten der beiden Operanden ist.Thus the absolute value of the result is the largest possible integer that is less than or equal to the absolute value of the quotient of the two operands. Das Ergebnis ist 0 (null) oder positiv, wenn die beiden Operanden das gleiche Vorzeichen aufweisen und 0 (null) oder negativ ist, wenn die beiden Operanden gegenteilige Vorzeichen verfügen.The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs.

    Wenn der linke Operand der kleinste darstellbare int -oder long -Wert und der rechte Operand ist -1 , tritt ein Überlauf auf.If the left operand is the smallest representable int or long value and the right operand is -1, an overflow occurs. In einem checked Kontext bewirkt dies, System.ArithmeticException dass eine (oder eine Unterklasse davon) ausgelöst wird.In a checked context, this causes a System.ArithmeticException (or a subclass thereof) to be thrown. In einem unchecked Kontext ist die Implementierung definiert, ob ein System.ArithmeticException (oder eine Unterklasse) ausgelöst wird, oder der Überlauf wird nicht gemeldet, und der resultierende Wert ist der des linken Operanden.In an unchecked context, it is implementation-defined as to whether a System.ArithmeticException (or a subclass thereof) is thrown or the overflow goes unreported with the resulting value being that of the left operand.

  • Gleit Komma Division:Floating-point division:

    float operator /(float x, float y);
    double operator /(double x, double y);
    

    Der Quotienten wird gemäß den Regeln der IEEE 754-Arithmetik berechnet.The quotient is computed according to the rules of IEEE 754 arithmetic. In der folgenden Tabelle sind die Ergebnisse für alle möglichen Kombinationen aus endlichen Werten ungleich Null, Nullen, unendlichen Werten und NaN-Werten aufgeführt.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. In der Tabelle sind x und y positive endliche Werte.In the table, x and y are positive finite values. z ist das Ergebnis von x / y.z is the result of x / y. Wenn das Ergebnis für den Zieltyp zu groß ist, ist z ein unendlicher Wert.If the result is too large for the destination type, z is infinity. Wenn das Ergebnis für den Zieltyp zu klein ist, ist z Null.If the result is too small for the destination type, z is zero.

    +y+y -y-y +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    +x+x +z+z -Z-z +inf+inf -inf-inf +0+0 -0-0 NaNNaN
    -X-x -Z-z +z+z -inf-inf +inf+inf -0-0 +0+0 NaNNaN
    +0+0 +0+0 -0-0 NaNNaN NaNNaN +0+0 -0-0 NaNNaN
    -0-0 -0-0 +0+0 NaNNaN NaNNaN -0-0 +0+0 NaNNaN
    +inf+inf +inf+inf -inf-inf +inf+inf -inf-inf NaNNaN NaNNaN NaNNaN
    -inf-inf -inf-inf +inf+inf -inf-inf +inf+inf NaNNaN NaNNaN NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Dezimale Division:Decimal division:

    decimal operator /(decimal x, decimal y);
    

    Wenn der Wert des rechten Operanden 0 (null) ist, wird eine ausgelöst System.DivideByZeroException .If the value of the right operand is zero, a System.DivideByZeroException is thrown. Wenn der resultierende Wert zu groß für die Darstellung im- decimal Format ist, System.OverflowException wird eine ausgelöst.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Wenn der Ergebniswert zu klein ist, um im decimal Format darzustellen, ist das Ergebnis 0 (null).If the result value is too small to represent in the decimal format, the result is zero. Die Skala des Ergebnisses ist die kleinste Skala, die ein Ergebnis mit dem nächstgelegenen darstellbaren Dezimalwert dem tatsächlichen mathematischen Ergebnis beibehält.The scale of the result is the smallest scale that will preserve a result equal to the nearest representable decimal value to the true mathematical result.

    Die Dezimal Division entspricht der Verwendung des Divisions Operators vom Typ System.Decimal .Decimal division is equivalent to using the division operator of type System.Decimal.

RestoperatorRemainder operator

Bei einem Vorgang des Formulars x % y wird die binäre Operator Überladungs Auflösung (binäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form x % y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Die Operanden werden in die Parametertypen des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Die vordefinierten Rest-Operatoren sind unten aufgeführt.The predefined remainder operators are listed below. Die Operatoren berechnen alle den Rest der Division zwischen x und y .The operators all compute the remainder of the division between x and y.

  • Ganzzahliger Rest:Integer remainder:

    int operator %(int x, int y);
    uint operator %(uint x, uint y);
    long operator %(long x, long y);
    ulong operator %(ulong x, ulong y);
    

    Das Ergebnis von x % y ist der Wert, der von erzeugt wird x - (x / y) * y .The result of x % y is the value produced by x - (x / y) * y. Wenn y 0 (null) ist, wird eine ausgelöst System.DivideByZeroException .If y is zero, a System.DivideByZeroException is thrown.

    Wenn der linke Operand der kleinste int -oder long -Wert und der rechte Operand ist -1 , System.OverflowException wird eine ausgelöst.If the left operand is the smallest int or long value and the right operand is -1, a System.OverflowException is thrown. In keinem Fall löst x % y eine Ausnahme aus, bei der x / y keine Ausnahme ausgelöst wird.In no case does x % y throw an exception where x / y would not throw an exception.

  • Gleit Komma Restwert:Floating-point remainder:

    float operator %(float x, float y);
    double operator %(double x, double y);
    

    In der folgenden Tabelle sind die Ergebnisse für alle möglichen Kombinationen aus endlichen Werten ungleich Null, Nullen, unendlichen Werten und NaN-Werten aufgeführt.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. In der Tabelle sind x und y positive endliche Werte.In the table, x and y are positive finite values. z Das Ergebnis von x % y und wird als berechnet x - n * y , wobei n die größtmögliche Ganzzahl ist, die kleiner oder gleich ist x / y .z is the result of x % y and is computed as x - n * y, where n is the largest possible integer that is less than or equal to x / y. Diese Methode zum Berechnen des Restwerts entspricht der für ganzzahligen Operanden, unterscheidet sich jedoch von der IEEE 754-Definition (bei der n es sich um die ganze Zahl handelt, die am nächsten ist x / y ).This method of computing the remainder is analogous to that used for integer operands, but differs from the IEEE 754 definition (in which n is the integer closest to x / y).

    +y+y -y-y +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    +x+x +z+z +z+z NaNNaN NaNNaN xx xx NaNNaN
    -X-x -Z-z -Z-z NaNNaN NaNNaN -X-x -X-x NaNNaN
    +0+0 +0+0 +0+0 NaNNaN NaNNaN +0+0 +0+0 NaNNaN
    -0-0 -0-0 -0-0 NaNNaN NaNNaN -0-0 -0-0 NaNNaN
    +inf+inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
    -inf-inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Dezimal Restwert:Decimal remainder:

    decimal operator %(decimal x, decimal y);
    

    Wenn der Wert des rechten Operanden 0 (null) ist, wird eine ausgelöst System.DivideByZeroException .If the value of the right operand is zero, a System.DivideByZeroException is thrown. Die Dezimalstellen des Ergebnisses, vor der Rundung, sind die größere der Skalen der beiden Operanden, und das Vorzeichen des Ergebnisses ist, wenn ungleich NULL, mit dem von identisch x .The scale of the result, before any rounding, is the larger of the scales of the two operands, and the sign of the result, if non-zero, is the same as that of x.

    Der Dezimal Rest entspricht der Verwendung des Rest-Operators vom Typ System.Decimal .Decimal remainder is equivalent to using the remainder operator of type System.Decimal.

AdditionsoperatorAddition operator

Bei einem Vorgang des Formulars x + y wird die binäre Operator Überladungs Auflösung (binäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form x + y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Die Operanden werden in die Parametertypen des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Die vordefinierten Additions Operatoren sind unten aufgeführt.The predefined addition operators are listed below. Für numerische und Enumerationstypen berechnen die vordefinierten Additions Operatoren die Summe der beiden Operanden.For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. Wenn ein oder beide Operanden vom Typ Zeichenfolge sind, verketten die vordefinierten Additions Operatoren die Zeichen folgen Darstellung der Operanden.When one or both operands are of type string, the predefined addition operators concatenate the string representation of the operands.

  • Ganzzahlige Addition:Integer addition:

    int operator +(int x, int y);
    uint operator +(uint x, uint y);
    long operator +(long x, long y);
    ulong operator +(ulong x, ulong y);
    

    In einem checked Kontext wird eine ausgelöst, wenn die Summe außerhalb des Bereichs des Ergebnis Typs liegt System.OverflowException .In a checked context, if the sum is outside the range of the result type, a System.OverflowException is thrown. In einem unchecked Kontext werden Überläufe nicht gemeldet, und alle signifikanten höherwertigen Bits außerhalb des Bereichs des Ergebnis Typs werden verworfen.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Gleit Komma Addition:Floating-point addition:

    float operator +(float x, float y);
    double operator +(double x, double y);
    

    Die Summe wird gemäß den Regeln der IEEE 754-Arithmetik berechnet.The sum is computed according to the rules of IEEE 754 arithmetic. In der folgenden Tabelle sind die Ergebnisse für alle möglichen Kombinationen aus endlichen Werten ungleich Null, Nullen, unendlichen Werten und NaN-Werten aufgeführt.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. In der Tabelle sind x und y endliche Werte ungleich Null, und z ist das Ergebnis aus x + y.In the table, x and y are nonzero finite values, and z is the result of x + y. Wenn x und y die gleiche Größe jedoch andere Vorzeichen haben, ist z eine positive Null.If x and y have the same magnitude but opposite signs, z is positive zero. Wenn zu x + y groß ist, um im Zieltyp darzustellen, z ist ein Unendlichkeits Wert mit demselben Vorzeichen wie x + y .If x + y is too large to represent in the destination type, z is an infinity with the same sign as x + y.

    Yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    wx zz xx xx +inf+inf -inf-inf NaNNaN
    +0+0 Yy +0+0 +0+0 +inf+inf -inf-inf NaNNaN
    -0-0 Yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    +inf+inf +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN NaNNaN
    -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN -inf-inf NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Dezimal Addition:Decimal addition:

    decimal operator +(decimal x, decimal y);
    

    Wenn der resultierende Wert zu groß für die Darstellung im- decimal Format ist, System.OverflowException wird eine ausgelöst.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Die Dezimalstellen des Ergebnisses, vor der Rundung, sind die größere der Skalen der beiden Operanden.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    Die Dezimal Addition entspricht der Verwendung des Additions Operators vom Typ System.Decimal .Decimal addition is equivalent to using the addition operator of type System.Decimal.

  • Enumerationsaddition.Enumeration addition. Jeder Enumerationstyp stellt implizit die folgenden vordefinierten Operatoren bereit, wobei E der Enumerationstyp und U der zugrunde liegende Typ von ist E :Every enumeration type implicitly provides the following predefined operators, where E is the enum type, and U is the underlying type of E:

    E operator +(E x, U y);
    E operator +(U x, E y);
    

    Zur Laufzeit werden diese Operatoren genau wie ausgewertet (E)((U)x + (U)y) .At run-time these operators are evaluated exactly as (E)((U)x + (U)y).

  • Verkettung von Zeichen folgen:String concatenation:

    string operator +(string x, string y);
    string operator +(string x, object y);
    string operator +(object x, string y);
    

    Diese über Ladungen des binären + Operators führen die Verkettung von Zeichen folgen aus.These overloads of the binary + operator perform string concatenation. Wenn ein Operand der Zeichen folgen Verkettung ist null , wird eine leere Zeichenfolge ersetzt.If an operand of string concatenation is null, an empty string is substituted. Andernfalls wird jedes nicht-Zeichen folgen Argument in seine Zeichen folgen Darstellung konvertiert, indem die ToString vom Typ geerbte virtuelle Methode aufgerufen wird object .Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. Wenn ToString zurückgibt null , wird eine leere Zeichenfolge ersetzt.If ToString returns null, an empty string is substituted.

    using System;
    
    class Test
    {
        static void Main() {
            string s = null;
            Console.WriteLine("s = >" + s + "<");        // displays s = ><
            int i = 1;
            Console.WriteLine("i = " + i);               // displays i = 1
            float f = 1.2300E+15F;
            Console.WriteLine("f = " + f);               // displays f = 1.23E+15
            decimal d = 2.900m;
            Console.WriteLine("d = " + d);               // displays d = 2.900
        }
    }
    

    Das Ergebnis des Zeichenfolgenverkettungs-Operators ist eine Zeichenfolge, die aus den Zeichen des linken Operanden besteht, gefolgt von den Zeichen des rechten Operanden. Der Operator für die Zeichen folgen Verkettung gibt niemals einen null Wert zurück. Eine System.OutOfMemoryException kann ausgelöst werden, wenn nicht genügend Arbeitsspeicher zur Verfügung steht, um die resultierende Zeichenfolge zuzuordnen.A System.OutOfMemoryException may be thrown if there is not enough memory available to allocate the resulting string.

  • Delegatkombination.Delegate combination. Jeder Delegattyp stellt implizit den folgenden vordefinierten Operator bereit, wobei D der Delegattyp ist:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator +(D x, D y);
    

    Der binäre + Operator führt eine Delegatkombination aus, wenn beide Operanden einen Delegattyp haben D .The binary + operator performs delegate combination when both operands are of some delegate type D. (Wenn die Operanden unterschiedliche Delegattypen aufweisen, tritt ein Bindungs Zeitfehler auf.) Wenn der erste Operand ist null , ist das Ergebnis der Operation der Wert des zweiten Operanden (auch wenn dies ebenfalls der Wert ist null ).(If the operands have different delegate types, a binding-time error occurs.) If the first operand is null, the result of the operation is the value of the second operand (even if that is also null). Andernfalls ist der zweite Operand, wenn der zweite Operand ist null , das Ergebnis des Vorgangs der Wert des ersten Operanden.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. Andernfalls ist das Ergebnis des Vorgangs eine neue Delegatinstanz, die beim Aufrufen den ersten Operanden aufruft und dann den zweiten Operanden aufruft.Otherwise, the result of the operation is a new delegate instance that, when invoked, invokes the first operand and then invokes the second operand. Beispiele für die Kombination von Delegaten finden Sie unter Subtraktions Operator und Delegataufruf. For examples of delegate combination, see Subtraction operator and Delegate invocation. Da System.Delegate kein Delegattyp ist, operator  + ist für ihn nicht definiert.Since System.Delegate is not a delegate type, operator + is not defined for it.

SubtraktionsoperatorSubtraction operator

Bei einem Vorgang des Formulars x - y wird die binäre Operator Überladungs Auflösung (binäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form x - y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Die Operanden werden in die Parametertypen des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Die vordefinierten Subtraktions Operatoren sind unten aufgeführt.The predefined subtraction operators are listed below. Die Operatoren, die alle von subtrahieren y x .The operators all subtract y from x.

  • Ganzzahlige Subtraktion:Integer subtraction:

    int operator -(int x, int y);
    uint operator -(uint x, uint y);
    long operator -(long x, long y);
    ulong operator -(ulong x, ulong y);
    

    Wenn sich checked der Unterschied in einem Kontext außerhalb des Bereichs des Ergebnis Typs befindet, wird eine ausgelöst System.OverflowException .In a checked context, if the difference is outside the range of the result type, a System.OverflowException is thrown. In einem unchecked Kontext werden Überläufe nicht gemeldet, und alle signifikanten höherwertigen Bits außerhalb des Bereichs des Ergebnis Typs werden verworfen.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Gleit Komma Subtraktion:Floating-point subtraction:

    float operator -(float x, float y);
    double operator -(double x, double y);
    

    Der Unterschied wird gemäß den Regeln der IEEE 754-Arithmetik berechnet.The difference is computed according to the rules of IEEE 754 arithmetic. In der folgenden Tabelle werden die Ergebnisse aller möglichen Kombinationen von nicht NULL Endwerten, Nullen, Infinities und Nane aufgelistet.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaNs. In der Tabelle sind x und y endliche Werte ungleich Null, und z ist das Ergebnis aus x - y.In the table, x and y are nonzero finite values, and z is the result of x - y. Wenn x und y gleich sind, ist z eine positive Null.If x and y are equal, z is positive zero. Wenn zu x - y groß ist, um im Zieltyp darzustellen, z ist ein Unendlichkeits Wert mit demselben Vorzeichen wie x - y .If x - y is too large to represent in the destination type, z is an infinity with the same sign as x - y.

    Yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    wx zz xx xx -inf-inf +inf+inf NaNNaN
    +0+0 -y-y +0+0 +0+0 -inf-inf +inf+inf NaNNaN
    -0-0 -y-y -0-0 +0+0 -inf-inf +inf+inf NaNNaN
    +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN +inf+inf NaNNaN
    -inf-inf -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Dezimale Subtraktion:Decimal subtraction:

    decimal operator -(decimal x, decimal y);
    

    Wenn der resultierende Wert zu groß für die Darstellung im- decimal Format ist, System.OverflowException wird eine ausgelöst.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Die Dezimalstellen des Ergebnisses, vor der Rundung, sind die größere der Skalen der beiden Operanden.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    Die dezimale Subtraktion entspricht der Verwendung des Subtraktions Operators vom Typ System.Decimal .Decimal subtraction is equivalent to using the subtraction operator of type System.Decimal.

  • Enumerationssubtraktion.Enumeration subtraction. Jeder Enumerationstyp stellt implizit den folgenden vordefinierten Operator bereit, wobei E der Enumerationstyp und U der zugrunde liegende Typ von ist E :Every enumeration type implicitly provides the following predefined operator, where E is the enum type, and U is the underlying type of E:

    U operator -(E x, E y);
    

    Dieser Operator wird genau wie ausgewertet (U)((U)x - (U)y) .This operator is evaluated exactly as (U)((U)x - (U)y). Mit anderen Worten, der-Operator berechnet den Unterschied zwischen den Ordinalwerten von x und y , und der Ergebnistyp ist der zugrunde liegende Typ der Enumeration.In other words, the operator computes the difference between the ordinal values of x and y, and the type of the result is the underlying type of the enumeration.

    E operator -(E x, U y);
    

    Dieser Operator wird genau wie ausgewertet (E)((U)x - y) .This operator is evaluated exactly as (E)((U)x - y). Mit anderen Worten, der Operator subtrahiert einen Wert vom zugrunde liegenden Typ der Enumeration und gibt einen Wert der-Enumeration aus.In other words, the operator subtracts a value from the underlying type of the enumeration, yielding a value of the enumeration.

  • Entfernen von Delegaten.Delegate removal. Jeder Delegattyp stellt implizit den folgenden vordefinierten Operator bereit, wobei D der Delegattyp ist:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator -(D x, D y);
    

    Der binäre - Operator führt eine Delegatentfernung aus, wenn beide Operanden einen Delegattyp haben D .The binary - operator performs delegate removal when both operands are of some delegate type D. Wenn die Operanden unterschiedliche Delegattypen aufweisen, tritt ein Bindungs Zeitfehler auf.If the operands have different delegate types, a binding-time error occurs. Ist der erste Operand null, ist das Ergebnis des Vorgangs null.If the first operand is null, the result of the operation is null. Andernfalls ist der zweite Operand, wenn der zweite Operand ist null , das Ergebnis des Vorgangs der Wert des ersten Operanden.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. Andernfalls stellen beide Operanden Aufruf Listen (Delegatdeklarationen) dar, die über mindestens einen Eintrag verfügen, und das Ergebnis ist eine neue Aufruf Liste, die aus der ersten Operanden Liste besteht, aus der die Einträge des zweiten Operanden entfernt wurden, vorausgesetzt, die Liste des zweiten Operanden ist eine ordnungsgemäße zusammenhängende unter Liste der ersten.Otherwise, both operands represent invocation lists (Delegate declarations) having one or more entries, and the result is a new invocation list consisting of the first operand's list with the second operand's entries removed from it, provided the second operand's list is a proper contiguous sublist of the first's. (Um die Übereinstimmung zu ermitteln, werden die entsprechenden Einträge als für den Delegat-Gleichheits Operator (Delegat-Gleichheits Operatoren) verglichen.) Andernfalls ist das Ergebnis der Wert des linken Operanden.(To determine sublist equality, corresponding entries are compared as for the delegate equality operator (Delegate equality operators).) Otherwise, the result is the value of the left operand. Die Listen der Operanden werden im Prozess nicht geändert.Neither of the operands' lists is changed in the process. Wenn die Liste des zweiten Operanden mit mehreren Unterlisten zusammenhängender Einträge in der Liste der ersten Operanden übereinstimmt, wird die am weitesten rechts gerichtete unter Liste von zusammenhängenden Einträgen entfernt.If the second operand's list matches multiple sublists of contiguous entries in the first operand's list, the right-most matching sublist of contiguous entries is removed. Sollte durch die Entfernung eine leere Liste entstehen, ist das Ergebnis null.If removal results in an empty list, the result is null. Beispiel:For example:

    delegate void D(int x);
    
    class C
    {
        public static void M1(int i) { /* ... */ }
        public static void M2(int i) { /* ... */ }
    }
    
    class Test
    {
        static void Main() { 
            D cd1 = new D(C.M1);
            D cd2 = new D(C.M2);
            D cd3 = cd1 + cd2 + cd2 + cd1;   // M1 + M2 + M2 + M1
            cd3 -= cd1;                      // => M1 + M2 + M2
    
            cd3 = cd1 + cd2 + cd2 + cd1;     // M1 + M2 + M2 + M1
            cd3 -= cd1 + cd2;                // => M2 + M1
    
            cd3 = cd1 + cd2 + cd2 + cd1;     // M1 + M2 + M2 + M1
            cd3 -= cd2 + cd2;                // => M1 + M1
    
            cd3 = cd1 + cd2 + cd2 + cd1;     // M1 + M2 + M2 + M1
            cd3 -= cd2 + cd1;                // => M1 + M2
    
            cd3 = cd1 + cd2 + cd2 + cd1;     // M1 + M2 + M2 + M1
            cd3 -= cd1 + cd1;                // => M1 + M2 + M2 + M1
        }
    }
    

SchiebeoperatorenShift operators

Die << >> Operatoren und werden verwendet, um Bitverschiebungs Vorgänge auszuführen.The << and >> operators are used to perform bit shifting operations.

shift_expression
    : additive_expression
    | shift_expression '<<' additive_expression
    | shift_expression right_shift additive_expression
    ;

Wenn ein Operand eines shift_expression den Kompilier Zeittyp aufweist dynamic , wird der Ausdruck dynamisch gebunden (dynamische Bindung).If an operand of a shift_expression has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In diesem Fall ist der Kompilier Zeittyp des Ausdrucks dynamic , und die unten beschriebene Auflösung erfolgt zur Laufzeit mit dem Lauf Zeittyp der Operanden, die den Kompilier Zeittyp aufweisen dynamic .In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

Bei einem Vorgang des Formulars x << count oder x >> count wird die binäre Operator Überladungs Auflösung (binäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form x << count or x >> count, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Die Operanden werden in die Parametertypen des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Beim Deklarieren eines überladenen Verschiebungs Operators muss der Typ des ersten Operanden immer die Klasse oder Struktur sein, die die Operator Deklaration enthält, und der Typ des zweiten Operanden muss immer sein int .When declaring an overloaded shift operator, the type of the first operand must always be the class or struct containing the operator declaration, and the type of the second operand must always be int.

Die vordefinierten Shift-Operatoren sind unten aufgeführt.The predefined shift operators are listed below.

  • Nach links verschieben:Shift left:

    int operator <<(int x, int count);
    uint operator <<(uint x, int count);
    long operator <<(long x, int count);
    ulong operator <<(ulong x, int count);
    

    Der << Operator verschiebt x nach links um eine Anzahl von Bits, die wie unten beschrieben berechnet werden.The << operator shifts x left by a number of bits computed as described below.

    Die höherwertigen Bits außerhalb des Bereichs des Ergebnis Typs von x werden verworfen, die restlichen Bits werden nach links verschoben, und die unteren leeren Bitpositionen werden auf 0 (null) festgelegt.The high-order bits outside the range of the result type of x are discarded, the remaining bits are shifted left, and the low-order empty bit positions are set to zero.

  • Nach rechts verschieben:Shift right:

    int operator >>(int x, int count);
    uint operator >>(uint x, int count);
    long operator >>(long x, int count);
    ulong operator >>(ulong x, int count);
    

    Der >> Operator verschiebt sich x nach rechts um eine Anzahl von Bits, die wie unten beschrieben berechnet werden.The >> operator shifts x right by a number of bits computed as described below.

    Wenn x int den Typ oder aufweist long , werden die nieder wertigen Bits von x verworfen, die restlichen Bits werden nach rechts verschoben, und die übergeordnete leere Bitpositionen werden auf 0 (null) festgelegt, wenn x nicht negativ ist, und auf einen Wert festgelegt, wenn x negativ ist.When x is of type int or long, the low-order bits of x are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero if x is non-negative and set to one if x is negative.

    Wenn x uint den Typ oder aufweist ulong , werden die nieder wertigen Bits von x verworfen, die restlichen Bits werden nach rechts verschoben, und die obersten leeren Bitpositionen werden auf 0 (null) festgelegt.When x is of type uint or ulong, the low-order bits of x are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero.

Für die vordefinierten Operatoren wird die Anzahl der zu Verschiebungs Bits wie folgt berechnet:For the predefined operators, the number of bits to shift is computed as follows:

  • Wenn der Typ von x int oder ist uint , wird die UMSCHALT Anzahl durch die nieder wertigen fünf Bits von angegeben count .When the type of x is int or uint, the shift count is given by the low-order five bits of count. Mit anderen Worten: die UMSCHALT Anzahl wird aus berechnet count & 0x1F .In other words, the shift count is computed from count & 0x1F.
  • Wenn der Typ von x long oder ist ulong , wird die UMSCHALT Anzahl durch die nieder wertigen sechs Bits von angegeben count .When the type of x is long or ulong, the shift count is given by the low-order six bits of count. Mit anderen Worten: die UMSCHALT Anzahl wird aus berechnet count & 0x3F .In other words, the shift count is computed from count & 0x3F.

Wenn die resultierende Verschiebungs Anzahl 0 (null) ist, geben die Schiebe Operatoren einfach den Wert von zurück x .If the resulting shift count is zero, the shift operators simply return the value of x.

Verschiebungs Vorgänge verursachen niemals Überläufe und erzeugen dieselben Ergebnisse in checked den unchecked Kontexten und.Shift operations never cause overflows and produce the same results in checked and unchecked contexts.

Wenn der linke Operand des Operators einen ganzzahligen >> Typ mit Vorzeichen hat, führt der Operator eine arithmetische Verschiebung nach rechts aus, in der der Wert des signifikantesten Bits (das Signier Bit) des Operanden an die übergeordnete leere Bitpositionen weitergegeben wird.When the left operand of the >> operator is of a signed integral type, the operator performs an arithmetic shift right wherein the value of the most significant bit (the sign bit) of the operand is propagated to the high-order empty bit positions. Wenn der linke Operand des Operators einen ganzzahligen >> Typ ohne Vorzeichen aufweist, führt der Operator eine logische Schiebe nach rechts aus, bei der die Positionen für die hohe Reihenfolge von leeren Bitpositionen immer auf NULL festgelegt sind.When the left operand of the >> operator is of an unsigned integral type, the operator performs a logical shift right wherein high-order empty bit positions are always set to zero. Explizite Umwandlungen können verwendet werden, um den umgekehrten Vorgang von auszuführen, der vom Operanden-Typ abgeleitet wird.To perform the opposite operation of that inferred from the operand type, explicit casts can be used. Wenn z. b. x eine Variable vom Typ ist int , führt der Vorgang unchecked((int)((uint)x >> y)) eine logische Verschiebung rechts von aus x .For example, if x is a variable of type int, the operation unchecked((int)((uint)x >> y)) performs a logical shift right of x.

Relationale und TyptestoperatorenRelational and type-testing operators

Die == != < Operatoren,,, > , <= , >= is und as werden als relationale und Typtest Operatoren bezeichnet.The ==, !=, <, >, <=, >=, is and as operators are called the relational and type-testing operators.

relational_expression
    : shift_expression
    | relational_expression '<' shift_expression
    | relational_expression '>' shift_expression
    | relational_expression '<=' shift_expression
    | relational_expression '>=' shift_expression
    | relational_expression 'is' type
    | relational_expression 'as' type
    ;

equality_expression
    : relational_expression
    | equality_expression '==' relational_expression
    | equality_expression '!=' relational_expression
    ;

Der is -Operator wird im is-Operator beschrieben, und der- as Operator wird im as-Operatorbeschrieben.The is operator is described in The is operator and the as operator is described in The as operator.

Die == != < Operatoren,,, > <= und >= sind Vergleichs Operatoren.The ==, !=, <, >, <= and >= operators are comparison operators.

Wenn ein Operand eines Vergleichs Operators den Kompilier Zeittyp aufweist dynamic , wird der Ausdruck dynamisch gebunden (dynamische Bindung).If an operand of a comparison operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In diesem Fall ist der Kompilier Zeittyp des Ausdrucks dynamic , und die unten beschriebene Auflösung erfolgt zur Laufzeit mit dem Lauf Zeittyp der Operanden, die den Kompilier Zeittyp aufweisen dynamic .In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

Bei einem Vorgang der Form x op y , bei dem op ein Vergleichs Operator ist, wird die Überladungs Auflösung (binäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form x op y, where op is a comparison operator, overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Die Operanden werden in die Parametertypen des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Die vordefinierten Vergleichs Operatoren werden in den folgenden Abschnitten beschrieben.The predefined comparison operators are described in the following sections. Alle vordefinierten Vergleichs Operatoren geben ein Ergebnis vom Typ zurück bool , wie in der folgenden Tabelle beschrieben.All predefined comparison operators return a result of type bool, as described in the following table.

VorgangOperation ErgebnisResult
x == y true``x, wenn gleich ist y , false andernfalls.true if x is equal to y, false otherwise
x != y true , wenn ungleich x ist y , false andernfalls.true if x is not equal to y, false otherwise
x < y true, wenn x kleiner ist als y, sonst falsetrue if x is less than y, false otherwise
x > y true, wenn x größer ist als y, sonst falsetrue if x is greater than y, false otherwise
x <= y true, wenn x kleiner als oder gleich y, sonst falsetrue if x is less than or equal to y, false otherwise
x >= y true, wenn x größer als oder gleich y, sonst falsetrue if x is greater than or equal to y, false otherwise

Integer-Vergleichs OperatorenInteger comparison operators

Die vordefinierten ganzzahligen Vergleichs Operatoren lauten wie folgt:The predefined integer comparison operators are:

bool operator ==(int x, int y);
bool operator ==(uint x, uint y);
bool operator ==(long x, long y);
bool operator ==(ulong x, ulong y);

bool operator !=(int x, int y);
bool operator !=(uint x, uint y);
bool operator !=(long x, long y);
bool operator !=(ulong x, ulong y);

bool operator <(int x, int y);
bool operator <(uint x, uint y);
bool operator <(long x, long y);
bool operator <(ulong x, ulong y);

bool operator >(int x, int y);
bool operator >(uint x, uint y);
bool operator >(long x, long y);
bool operator >(ulong x, ulong y);

bool operator <=(int x, int y);
bool operator <=(uint x, uint y);
bool operator <=(long x, long y);
bool operator <=(ulong x, ulong y);

bool operator >=(int x, int y);
bool operator >=(uint x, uint y);
bool operator >=(long x, long y);
bool operator >=(ulong x, ulong y);

Jeder dieser Operatoren vergleicht die numerischen Werte der beiden ganzzahligen Operanden und gibt einen bool Wert zurück, der angibt, ob die jeweilige Beziehung true oder ist false .Each of these operators compares the numeric values of the two integer operands and returns a bool value that indicates whether the particular relation is true or false.

Vergleichs Operatoren für Gleit Komma ZahlenFloating-point comparison operators

Die vordefinierten Gleit Komma Vergleichs Operatoren lauten wie folgt:The predefined floating-point comparison operators are:

bool operator ==(float x, float y);
bool operator ==(double x, double y);

bool operator !=(float x, float y);
bool operator !=(double x, double y);

bool operator <(float x, float y);
bool operator <(double x, double y);

bool operator >(float x, float y);
bool operator >(double x, double y);

bool operator <=(float x, float y);
bool operator <=(double x, double y);

bool operator >=(float x, float y);
bool operator >=(double x, double y);

Die Operanden werden von den Operatoren gemäß den Regeln des IEEE 754-Standards verglichen:The operators compare the operands according to the rules of the IEEE 754 standard:

  • Wenn einer der beiden Operanden NaN ist, gilt das Ergebnis false für alle Operatoren mit Ausnahme != von, für die das Ergebnis ist true .If either operand is NaN, the result is false for all operators except !=, for which the result is true. Bei zwei-Operanden x != y erzeugt immer dasselbe Ergebnis wie !(x == y) .For any two operands, x != y always produces the same result as !(x == y). Wenn jedoch ein oder beide Operanden NaN sind, führen die < > <= Operatoren,, und >= nicht zu den gleichen Ergebnissen wie die logische Negation des umgekehrten Operators.However, when one or both operands are NaN, the <, >, <=, and >= operators do not produce the same results as the logical negation of the opposite operator. Wenn z. b. einer der beiden Optionen x und y NaN ist, dann x < y ist false , aber !(x >= y) ist true .For example, if either of x and y is NaN, then x < y is false, but !(x >= y) is true.

  • Wenn keiner der Operanden NaN ist, vergleichen die Operatoren die Werte der beiden Gleit Komma Operanden in Bezug auf die Reihenfolge.When neither operand is NaN, the operators compare the values of the two floating-point operands with respect to the ordering

    -inf < -max < ... < -min < -0.0 == +0.0 < +min < ... < +max < +inf
    

    min max dabei sind und die kleinsten und größten positiven Endwerte, die im angegebenen Gleit Komma Format dargestellt werden können.where min and max are the smallest and largest positive finite values that can be represented in the given floating-point format. Wichtige Auswirkungen dieser Reihenfolge:Notable effects of this ordering are:

    • Negative und positive Nullen gelten als gleich.Negative and positive zeros are considered equal.
    • Minus unendlich gilt als kleiner als alle anderen Werte, aber gleichbedeutend mit einem anderen negativen unendlich.A negative infinity is considered less than all other values, but equal to another negative infinity.
    • Eine positive Unendlichkeit gilt als größer als alle anderen Werte, aber gleichbedeutend mit einer anderen positiven unendlich.A positive infinity is considered greater than all other values, but equal to another positive infinity.

Dezimale Vergleichs OperatorenDecimal comparison operators

Die vordefinierten dezimalen Vergleichs Operatoren lauten wie folgt:The predefined decimal comparison operators are:

bool operator ==(decimal x, decimal y);
bool operator !=(decimal x, decimal y);
bool operator <(decimal x, decimal y);
bool operator >(decimal x, decimal y);
bool operator <=(decimal x, decimal y);
bool operator >=(decimal x, decimal y);

Jeder dieser Operatoren vergleicht die numerischen Werte der beiden Decimal-Operanden und gibt einen bool Wert zurück, der angibt, ob die jeweilige Beziehung true oder ist false .Each of these operators compares the numeric values of the two decimal operands and returns a bool value that indicates whether the particular relation is true or false. Jeder Dezimal Vergleich entspricht der Verwendung des entsprechenden relationalen or-Gleichheits Operators vom Typ System.Decimal .Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal.

Boolesche Gleichheits OperatorenBoolean equality operators

Die vordefinierten booleschen Gleichheits Operatoren lauten wie folgt:The predefined boolean equality operators are:

bool operator ==(bool x, bool y);
bool operator !=(bool x, bool y);

Das Ergebnis von == ist, true Wenn sowohl x als auch y sind true oder wenn sowohl x als y false auch gleich sind.The result of == is true if both x and y are true or if both x and y are false. Andernfalls ist das Ergebnis false.Otherwise, the result is false.

Das Ergebnis von != ist, false Wenn sowohl x als auch y sind true oder wenn sowohl x als y false auch gleich sind.The result of != is false if both x and y are true or if both x and y are false. Andernfalls ist das Ergebnis true.Otherwise, the result is true. Wenn die Operanden den Typ bool haben, != erzeugt der Operator dasselbe Ergebnis wie der ^ Operator.When the operands are of type bool, the != operator produces the same result as the ^ operator.

EnumerationsvergleichsoperatorenEnumeration comparison operators

Jeder Enumerationstyp stellt implizit die folgenden vordefinierten Vergleichs Operatoren bereit:Every enumeration type implicitly provides the following predefined comparison operators:

bool operator ==(E x, E y);
bool operator !=(E x, E y);
bool operator <(E x, E y);
bool operator >(E x, E y);
bool operator <=(E x, E y);
bool operator >=(E x, E y);

Das Ergebnis der Auswertung von x op y , wobei x und y Ausdrücke eines Enumerationstyps E mit einem zugrunde liegenden Typ sind U , und op ist einer der Vergleichs Operatoren, ist identisch mit dem Auswerten von ((U)x) op ((U)y) .The result of evaluating x op y, where x and y are expressions of an enumeration type E with an underlying type U, and op is one of the comparison operators, is exactly the same as evaluating ((U)x) op ((U)y). Mit anderen Worten, die Vergleichs Operatoren des Enumerationstyps vergleichen einfach die zugrunde liegenden ganzzahligen Werte der beiden Operanden.In other words, the enumeration type comparison operators simply compare the underlying integral values of the two operands.

Verweistyp-Gleichheits OperatorenReference type equality operators

Die vordefinierten Verweistyp-Gleichheits Operatoren sind:The predefined reference type equality operators are:

bool operator ==(object x, object y);
bool operator !=(object x, object y);

Die Operatoren geben das Ergebnis des Vergleichs der beiden Verweise auf Gleichheit oder nicht Gleichheit zurück.The operators return the result of comparing the two references for equality or non-equality.

Da die vordefinierten Verweistyp-Gleichheits Operatoren Operanden vom Typ akzeptieren object , gelten Sie für alle Typen, die keine anwendbaren Elemente und Member deklarieren operator == operator != .Since the predefined reference type equality operators accept operands of type object, they apply to all types that do not declare applicable operator == and operator != members. Im Gegensatz dazu Blenden alle anwendbaren benutzerdefinierten Gleichheits Operatoren die vordefinierten Verweistyp-Gleichheits Operatoren aus.Conversely, any applicable user-defined equality operators effectively hide the predefined reference type equality operators.

Die vordefinierten Verweistyp-Gleichheits Operatoren erfordern eine der folgenden:The predefined reference type equality operators require one of the following:

  • Beide Operanden sind ein Wert eines Typs, der bekanntermaßen eine reference_type oder das Literale ist null .Both operands are a value of a type known to be a reference_type or the literal null. Darüber hinaus ist eine explizite Verweis Konvertierung (explizite Verweis Konvertierungen) vom Typ eines der beiden Operanden bis zum Typ des anderen Operanden vorhanden.Furthermore, an explicit reference conversion (Explicit reference conversions) exists from the type of either operand to the type of the other operand.
  • Ein Operand ist ein Wert vom Typ, T wobei T eine type_parameter und der andere Operand das Literale ist null .One operand is a value of type T where T is a type_parameter and the other operand is the literal null. Außerdem T weist nicht die Werttyp Einschränkung auf.Furthermore T does not have the value type constraint.

Wenn eine dieser Bedingungen nicht zutrifft, tritt ein Fehler bei der Bindung auf.Unless one of these conditions are true, a binding-time error occurs. Wichtige Implikationen dieser Regeln sind:Notable implications of these rules are:

  • Es handelt sich um einen Bindungs Fehler, bei dem die vordefinierten Verweistyp-Gleichheits Operatoren verwendet werden, um zwei Verweise zu vergleichen, die bekanntermaßen bei der Bindungs Zeit unterschiedlich sind.It is a binding-time error to use the predefined reference type equality operators to compare two references that are known to be different at binding-time. Wenn die Bindungs Zeit Typen der Operanden z. b. zwei Klassentypen und sind A B und weder A noch B vom anderen abgeleitet sind, kann es unmöglich sein, dass die beiden Operanden auf das gleiche Objekt verweisen.For example, if the binding-time types of the operands are two class types A and B, and if neither A nor B derives from the other, then it would be impossible for the two operands to reference the same object. Daher wird der Vorgang als Bindungs Zeit Fehler betrachtet.Thus, the operation is considered a binding-time error.
  • Die vordefinierten Verweistyp-Gleichheits Operatoren lassen nicht zu, dass Werttyp Operanden verglichen werden.The predefined reference type equality operators do not permit value type operands to be compared. Daher ist es nicht möglich, Werte dieses Struktur Typs zu vergleichen, es sei denn, ein Strukturtyp deklariert seine eigenen Gleichheits Operatoren.Therefore, unless a struct type declares its own equality operators, it is not possible to compare values of that struct type.
  • Die vordefinierten Verweistyp-Gleichheits Operatoren bewirken nie, dass Boxing-Vorgänge für ihre Operanden ausgeführt werden.The predefined reference type equality operators never cause boxing operations to occur for their operands. Es wäre bedeutungslos, solche Boxing-Vorgänge auszuführen, da Verweise auf die neu zugeordneten geachtelten Instanzen notwendigerweise von allen anderen verweisen abweichen.It would be meaningless to perform such boxing operations, since references to the newly allocated boxed instances would necessarily differ from all other references.
  • Wenn ein Operand eines Typparameter Typs T mit verglichen wird null und der Lauf Zeittyp von T ein Werttyp ist, ist das Ergebnis des Vergleichs false .If an operand of a type parameter type T is compared to null, and the run-time type of T is a value type, the result of the comparison is false.

Im folgenden Beispiel wird überprüft, ob ein Argument eines nicht eingeschränkten Typparameter Typs ist null .The following example checks whether an argument of an unconstrained type parameter type is null.

class C<T>
{
    void F(T x) {
        if (x == null) throw new ArgumentNullException();
        ...
    }
}

Das x == null -Konstrukt ist zulässig T , obwohl einen Werttyp darstellen könnte, und das Ergebnis wird einfach als definiert, false Wenn T ein Werttyp ist.The x == null construct is permitted even though T could represent a value type, and the result is simply defined to be false when T is a value type.

Bei einem Vorgang im Formular x == y oder x != y , sofern zutreffend operator == oder operator != vorhanden, wählt die Operator Überladungs Auflösung (binäre Operator Überladungs Auflösung) diesen Operator anstelle des vordefinierten Verweistyp Gleichheits Operators aus.For an operation of the form x == y or x != y, if any applicable operator == or operator != exists, the operator overload resolution (Binary operator overload resolution) rules will select that operator instead of the predefined reference type equality operator. Es ist jedoch immer möglich, den vordefinierten Verweistyp Gleichheits Operator auszuwählen, indem eine oder beide der Operanden explizit in den Typ umgewandelt werden object .However, it is always possible to select the predefined reference type equality operator by explicitly casting one or both of the operands to type object. Das BeispielThe example

using System;

class Test
{
    static void Main() {
        string s = "Test";
        string t = string.Copy(s);
        Console.WriteLine(s == t);
        Console.WriteLine((object)s == t);
        Console.WriteLine(s == (object)t);
        Console.WriteLine((object)s == (object)t);
    }
}

erzeugt die Ausgabeproduces the output

True
False
False
False

Die s t Variablen und verweisen auf zwei unterschiedliche string Instanzen, die die gleichen Zeichen enthalten.The s and t variables refer to two distinct string instances containing the same characters. Der erste Vergleichswert True gibt an, dass der vordefinierte Zeichen folgen Gleichheits Operator (Zeichen folgen GleichheitsOperator) ausgewählt ist, wenn beide Operanden vom Typ sind string .The first comparison outputs True because the predefined string equality operator (String equality operators) is selected when both operands are of type string. Die verbleibenden Vergleiche werden alle ausgegeben, False da der vordefinierte Verweistyp Gleichheits Operator ausgewählt wird, wenn einer oder beide Operanden den Typ haben object .The remaining comparisons all output False because the predefined reference type equality operator is selected when one or both of the operands are of type object.

Beachten Sie, dass die oben beschriebene Technik für Werttypen nicht sinnvoll ist.Note that the above technique is not meaningful for value types. Das BeispielThe example

class Test
{
    static void Main() {
        int i = 123;
        int j = 123;
        System.Console.WriteLine((object)i == (object)j);
    }
}

gibt Ausgaben False aus, da die Umwandlungen Verweise auf zwei separate Instanzen von geboxten int Werten erstellen.outputs False because the casts create references to two separate instances of boxed int values.

Operatoren für Zeichen folgenString equality operators

Die vordefinierten Zeichen folgen-Gleichheits Operatoren sind:The predefined string equality operators are:

bool operator ==(string x, string y);
bool operator !=(string x, string y);

Zwei string Werte werden als gleich betrachtet, wenn eine der folgenden Punkte zutrifft:Two string values are considered equal when one of the following is true:

  • Beide Werte sind null .Both values are null.
  • Beide Werte sind Verweise ungleich NULL auf Zeichen folgen Instanzen, die identische Längen und identische Zeichen an jeder Zeichenposition aufweisen.Both values are non-null references to string instances that have identical lengths and identical characters in each character position.

Die Gleichheits Operatoren für Zeichen folgen vergleichen Zeichen folgen Werte anstelle von Zeichen folgen verweisen.The string equality operators compare string values rather than string references. Wenn zwei separate Zeichen folgen Instanzen genau dieselbe Zeichenfolge enthalten, sind die Werte der Zeichen folgen gleich, aber die Verweise unterscheiden sich.When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. Wie in Verweistyp Gleichheits Operatorenbeschrieben, können die Verweistyp-Gleichheits Operatoren verwendet werden, um Zeichen folgen Verweise anstelle von Zeichen folgen Werten zu vergleichen.As described in Reference type equality operators, the reference type equality operators can be used to compare string references instead of string values.

DelegatenoperatorenDelegate equality operators

Jeder Delegattyp stellt implizit die folgenden vordefinierten Vergleichs Operatoren bereit:Every delegate type implicitly provides the following predefined comparison operators:

bool operator ==(System.Delegate x, System.Delegate y);
bool operator !=(System.Delegate x, System.Delegate y);

Zwei Delegatinstanzen werden wie folgt als gleich betrachtet:Two delegate instances are considered equal as follows:

  • Wenn eine der Delegatinstanzen ist null , sind Sie nur dann gleich, wenn beide gleich sind null .If either of the delegate instances is null, they are equal if and only if both are null.
  • Wenn die Delegaten einen anderen Lauf Zeittyp aufweisen, sind Sie nie gleich.If the delegates have different run-time type they are never equal.
  • Wenn beide Delegatinstanzen über eine Aufruf Liste (Delegatdeklarationen) verfügen, sind diese Instanzen nur dann gleich, wenn Ihre Aufruf Listen dieselbe Länge aufweisen und jeder Eintrag in einer Aufruf Liste (wie unten definiert) dem entsprechenden Eintrag in der Reihenfolge in der Aufruf Liste eines anderen entspricht.If both of the delegate instances have an invocation list (Delegate declarations), those instances are equal if and only if their invocation lists are the same length, and each entry in one's invocation list is equal (as defined below) to the corresponding entry, in order, in the other's invocation list.

Die folgenden Regeln bestimmen die Gleichheit von Aufruf Listeneinträgen:The following rules govern the equality of invocation list entries:

  • Wenn zwei Aufruf Listeneinträge auf dieselbe statische Methode verweisen, sind die Einträge gleich.If two invocation list entries both refer to the same static method then the entries are equal.
  • Wenn zwei Aufruf Listeneinträge auf dieselbe nicht statische Methode im gleichen Zielobjekt verweisen (wie durch die Verweis Gleichheits Operatoren definiert), sind die Einträge gleich.If two invocation list entries both refer to the same non-static method on the same target object (as defined by the reference equality operators) then the entries are equal.
  • Aufruf Listeneinträge, die aus der Auswertung semantisch identischer anonymous_method_expression s oder lambda_expression s mit demselben (möglicherweise leeren) Satz erfasster externer Variablen Instanzen erstellt werden, sind zulässig (aber nicht erforderlich).Invocation list entries produced from evaluation of semantically identical anonymous_method_expression s or lambda_expression s with the same (possibly empty) set of captured outer variable instances are permitted (but not required) to be equal.

Gleichheits Operatoren und NULLEquality operators and null

Der == -Operator und der- != Operator gestatten einem Operanden einen Wert eines Typs, der NULL-Werte zulässt, und der andere als null Literalwert, auch wenn kein vordefinierter oder benutzerdefinierter Operator für den Vorgang vorhanden ist.The == and != operators permit one operand to be a value of a nullable type and the other to be the null literal, even if no predefined or user-defined operator (in unlifted or lifted form) exists for the operation.

Für einen Vorgang eines der FormulareFor an operation of one of the forms

x == null
null == x
x != null
null != x

dabei x ist ein Ausdruck eines Typs, der NULL-Werte zulässt, wenn die Operator Überladungs Auflösung (binäre Operator Überladungs Auflösung) keinen anwendbaren Operator findet, wird das Ergebnis stattdessen aus der- HasValue Eigenschaft von berechnet x .where x is an expression of a nullable type, if operator overload resolution (Binary operator overload resolution) fails to find an applicable operator, the result is instead computed from the HasValue property of x. Insbesondere werden die ersten beiden Formulare in übersetzt !x.HasValue , und die letzten beiden Formulare werden in übersetzt x.HasValue .Specifically, the first two forms are translated into !x.HasValue, and last two forms are translated into x.HasValue.

Der is-OperatorThe is operator

Der- is Operator wird verwendet, um dynamisch zu überprüfen, ob der Lauf Zeittyp eines Objekts mit einem angegebenen Typ kompatibel ist.The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. Das Ergebnis des Vorgangs E is T , wobei E ein Ausdruck und T ein Typ ist, ist ein boolescher Wert, der angibt, ob E erfolgreich T durch eine Verweis Konvertierung, eine Boxing-Konvertierung oder eine Unboxing-Konvertierung in den Typ konvertiert werden kann.The result of the operation E is T, where E is an expression and T is a type, is a boolean value indicating whether E can successfully be converted to type T by a reference conversion, a boxing conversion, or an unboxing conversion. Der Vorgang wird wie folgt ausgewertet, nachdem Typargumente für alle Typparameter ersetzt wurden:The operation is evaluated as follows, after type arguments have been substituted for all type parameters:

  • Wenn E eine anonyme Funktion ist, tritt ein Kompilierzeitfehler auf.If E is an anonymous function, a compile-time error occurs
  • Wenn E eine Methoden Gruppe oder das null Literale ist, wenn der Typ von E ein Verweistyp oder ein Werte zulässt-Typ ist und der Wert von E NULL ist, ist das Ergebnis false.If E is a method group or the null literal, of if the type of E is a reference type or a nullable type and the value of E is null, the result is false.
  • Stellen Sie andernfalls D den dynamischen Typ von E wie folgt dar:Otherwise, let D represent the dynamic type of E as follows:
    • Wenn der Typ von E ein Verweistyp ist, D ist der Lauf Zeittyp des instanzverweises von E .If the type of E is a reference type, D is the run-time type of the instance reference by E.
    • Wenn der Typ von E ein Typ ist, der NULL-Werte zulässt, D ist der zugrunde liegende Typ dieses Typs, der NULL-Werte zulässt.If the type of E is a nullable type, D is the underlying type of that nullable type.
    • Wenn der Typ von E ein Werttyp ist, der keine NULL-Werte zulässt, D ist der Typ von E .If the type of E is a non-nullable value type, D is the type of E.
  • Das Ergebnis des Vorgangs hängt von D und T wie folgt ab:The result of the operation depends on D and T as follows:
    • Wenn T ein Verweistyp ist, ist das Ergebnis true, wenn D und T denselben Typ haben, wenn D ein Verweistyp und eine implizite Verweis Konvertierung von D in vorhanden ist T , oder wenn D ein Werttyp und eine Boxingkonvertierung von D in vorhanden ist T .If T is a reference type, the result is true if D and T are the same type, if D is a reference type and an implicit reference conversion from D to T exists, or if D is a value type and a boxing conversion from D to T exists.
    • Wenn T ein Typ ist, der NULL-Werte zulässt, ist das Ergebnis true, wenn D der zugrunde liegende Typ von ist T .If T is a nullable type, the result is true if D is the underlying type of T.
    • Wenn T ein Werttyp ist, der keine NULL-Werte zulässt, ist das Ergebnis true, wenn D und T denselben Typ haben.If T is a non-nullable value type, the result is true if D and T are the same type.
    • Andernfalls ist das Ergebnis false.Otherwise, the result is false.

Beachten Sie, dass benutzerdefinierte Konvertierungen vom-Operator nicht berücksichtigt werden is .Note that user defined conversions, are not considered by the is operator.

Der as-OperatorThe as operator

Der- as Operator wird verwendet, um einen Wert explizit in einen angegebenen Verweistyp oder Werte zulässt-Typ zu konvertieren.The as operator is used to explicitly convert a value to a given reference type or nullable type. Anders als bei einem Umwandlungs Ausdruck (Cast-Ausdrücke) löst der as Operator nie eine Ausnahme aus.Unlike a cast expression (Cast expressions), the as operator never throws an exception. Wenn die angegebene Konvertierung nicht möglich ist, ist der resultierende Wert null .Instead, if the indicated conversion is not possible, the resulting value is null.

Bei einem Vorgang des Formulars E as T E muss ein Ausdruck sein, und er T muss ein Verweistyp sein, ein Typparameter, der als Verweistyp bekannt ist, oder ein Typ, der NULL-Werte zulässt.In an operation of the form E as T, E must be an expression and T must be a reference type, a type parameter known to be a reference type, or a nullable type. Außerdem muss mindestens einer der folgenden Punkte zutreffen. andernfalls tritt ein Kompilierzeitfehler auf:Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:

Wenn der Kompilier Zeittyp von E nicht ist dynamic , erzeugt der Vorgang E as T dasselbe Ergebnis wieIf the compile-time type of E is not dynamic, the operation E as T produces the same result as

E is T ? (T)(E) : (T)null

außer dass E nur einmal überprüft wird.except that E is only evaluated once. Es ist zu erwarten, dass der Compiler E as T eine Optimierung durchführt, um höchstens eine dynamische Typüberprüfung auszuführen, im Gegensatz zu den zwei dynamischen Typüberprüfungen, die von der obigen Erweiterung impliziert werden.The compiler can be expected to optimize E as T to perform at most one dynamic type check as opposed to the two dynamic type checks implied by the expansion above.

Wenn der Kompilier Zeittyp von den Wert E dynamic hat, ist der Operator im Gegensatz zum Cast Operator as nicht dynamisch gebunden (dynamische Bindung).If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound (Dynamic binding). Daher ist die Erweiterung in diesem Fall:Therefore the expansion in this case is:

E is T ? (T)(object)(E) : (T)null

Beachten Sie, dass einige Konvertierungen, wie z. b. benutzerdefinierte Konvertierungen, mit dem-Operator nicht möglich sind as und stattdessen mithilfe von Umwandlungs Ausdrücken ausgeführt werden.Note that some conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.

Im BeispielIn the example

class X
{

    public string F(object o) {
        return o as string;        // OK, string is a reference type
    }

    public T G<T>(object o) where T: Attribute {
        return o as T;             // Ok, T has a class constraint
    }

    public U H<U>(object o) {
        return o as U;             // Error, U is unconstrained 
    }
}

der Typparameter T von G ist bekannt, dass es sich um einen Verweistyp handelt, da er die-Klassen Einschränkung aufweist.the type parameter T of G is known to be a reference type, because it has the class constraint. Der Typparameter U von H ist jedoch nicht zulässig. Daher ist die Verwendung des- as Operators in unzulässig H .The type parameter U of H is not however; hence the use of the as operator in H is disallowed.

Logische OperatorenLogical operators

Die & ^ | Operatoren, und werden als logische Operatoren bezeichnet.The &, ^, and | operators are called the logical operators.

and_expression
    : equality_expression
    | and_expression '&' equality_expression
    ;

exclusive_or_expression
    : and_expression
    | exclusive_or_expression '^' and_expression
    ;

inclusive_or_expression
    : exclusive_or_expression
    | inclusive_or_expression '|' exclusive_or_expression
    ;

Wenn ein Operand eines logischen Operators den Kompilier Zeittyp aufweist dynamic , wird der Ausdruck dynamisch gebunden (dynamische Bindung).If an operand of a logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In diesem Fall ist der Kompilier Zeittyp des Ausdrucks dynamic , und die unten beschriebene Auflösung erfolgt zur Laufzeit mit dem Lauf Zeittyp der Operanden, die den Kompilier Zeittyp aufweisen dynamic .In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

Bei einem Vorgang im Formular x op y , bei dem op es sich um einen der logischen Operatoren handelt, wird die Überladungs Auflösung (binäre Operator Überladungs Auflösung) angewendet, um eine bestimmte Operator Implementierung auszuwählen.For an operation of the form x op y, where op is one of the logical operators, overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Die Operanden werden in die Parametertypen des ausgewählten Operators konvertiert, und der Ergebnistyp ist der Rückgabetyp des Operators.The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Die vordefinierten logischen Operatoren werden in den folgenden Abschnitten beschrieben.The predefined logical operators are described in the following sections.

Ganz Zahl logische OperatorenInteger logical operators

Die vordefinierten ganzzahligen logischen Operatoren lauten wie folgt:The predefined integer logical operators are:

int operator &(int x, int y);
uint operator &(uint x, uint y);
long operator &(long x, long y);
ulong operator &(ulong x, ulong y);

int operator |(int x, int y);
uint operator |(uint x, uint y);
long operator |(long x, long y);
ulong operator |(ulong x, ulong y);

int operator ^(int x, int y);
uint operator ^(uint x, uint y);
long operator ^(long x, long y);
ulong operator ^(ulong x, ulong y);

Der- & Operator berechnet die bitweise logische AND der beiden Operanden, der | -Operator berechnet die bitweise logische OR der beiden Operanden, und der- ^ Operator berechnet das bitweise logische exklusive-Element der beiden- OR Operanden.The & operator computes the bitwise logical AND of the two operands, the | operator computes the bitwise logical OR of the two operands, and the ^ operator computes the bitwise logical exclusive OR of the two operands. Von diesen Vorgängen können keine über Flüsse durchlaufen werden.No overflows are possible from these operations.

Logische EnumerationsoperatorenEnumeration logical operators

Jeder Enumerationstyp E stellt implizit die folgenden vordefinierten logischen Operatoren bereit:Every enumeration type E implicitly provides the following predefined logical operators:

E operator &(E x, E y);
E operator |(E x, E y);
E operator ^(E x, E y);

Das Ergebnis der Auswertung von x op y , wobei x und y Ausdrücke eines Enumerationstyps E mit einem zugrunde liegenden Typ sind U , und op ist einer der logischen Operatoren, ist identisch mit dem Auswerten von (E)((U)x op (U)y) .The result of evaluating x op y, where x and y are expressions of an enumeration type E with an underlying type U, and op is one of the logical operators, is exactly the same as evaluating (E)((U)x op (U)y). Mit anderen Worten: die logischen Operatoren des Enumerationstyps führen einfach die logische Operation für den zugrunde liegenden Typ der beiden Operanden aus.In other words, the enumeration type logical operators simply perform the logical operation on the underlying type of the two operands.

Logische boolesche OperatorenBoolean logical operators

Die vordefinierten booleschen logischen Operatoren lauten wie folgt:The predefined boolean logical operators are:

bool operator &(bool x, bool y);
bool operator |(bool x, bool y);
bool operator ^(bool x, bool y);

Das Ergebnis von x & y ist true, wenn sowohl x als auch y zu true ausgewertet werden.The result of x & y is true if both x and y are true. Andernfalls ist das Ergebnis false.Otherwise, the result is false.

Das Ergebnis von x | y ist, true Wenn entweder x oder y ist true .The result of x | y is true if either x or y is true. Andernfalls ist das Ergebnis false.Otherwise, the result is false.

Das Ergebnis von x ^ y ist true , wenn den Wert x true y hat und ist false , oder x ist false und ist y true .The result of x ^ y is true if x is true and y is false, or x is false and y is true. Andernfalls ist das Ergebnis false.Otherwise, the result is false. Wenn die Operanden vom Typ sind bool , ^ berechnet der Operator dasselbe Ergebnis wie der != Operator.When the operands are of type bool, the ^ operator computes the same result as the != operator.

Boolesche logische Operatoren, die NULL-Werte zulassenNullable boolean logical operators

Der booleschen-Typ, der NULL bool? -Werte zulässt, kann drei Werte, true , false und darstellen null und ist konzeptionell vergleichbar mit dem dreiwertigen Typ, der für boolesche Ausdrücke in SQL verwendet wird.The nullable boolean type bool? can represent three values, true, false, and null, and is conceptually similar to the three-valued type used for boolean expressions in SQL. Um sicherzustellen, dass die Ergebnisse, die von den & | bool? Operatoren und für Operanden erzeugt werden, mit der dreiwertigen Logik von SQL übereinstimmen, werden die folgenden vordefinierten Operatoren bereitgestellt:To ensure that the results produced by the & and | operators for bool? operands are consistent with SQL's three-valued logic, the following predefined operators are provided:

bool? operator &(bool? x, bool? y);
bool? operator |(bool? x, bool? y);

In der folgenden Tabelle werden die Ergebnisse aufgelistet, die von diesen Operatoren für alle Kombinationen der Werte true , und erzeugt werden false null .The following table lists the results produced by these operators for all combinations of the values true, false, and null.

x y x & y x | y
true true true true
true false false true
true null null true
false true false true
false false false false
false null false null
null true null true
null false false null
null null null null

Bedingte logische OperatorenConditional logical operators

Die Operatoren && und || werden als bedingte logische Operatoren bezeichnet.The && and || operators are called the conditional logical operators. Sie werden auch als "Kurzschluss" logische Operatoren bezeichnet.They are also called the "short-circuiting" logical operators.

conditional_and_expression
    : inclusive_or_expression
    | conditional_and_expression '&&' inclusive_or_expression
    ;

conditional_or_expression
    : conditional_and_expression
    | conditional_or_expression '||' conditional_and_expression
    ;

Die && || Operatoren und sind bedingte Versionen der & -und- | Operatoren:The && and || operators are conditional versions of the & and | operators:

  • Der-Vorgang x && y entspricht dem-Vorgang, mit dem Unterschied, x & y dass y nur ausgewertet wird, wenn x nicht ist false .The operation x && y corresponds to the operation x & y, except that y is evaluated only if x is not false.
  • Der-Vorgang x || y entspricht dem-Vorgang, mit dem Unterschied, x | y dass y nur ausgewertet wird, wenn x nicht ist true .The operation x || y corresponds to the operation x | y, except that y is evaluated only if x is not true.

Wenn ein Operand eines bedingten logischen Operators den Kompilier Zeittyp aufweist dynamic , wird der Ausdruck dynamisch gebunden (dynamische Bindung).If an operand of a conditional logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In diesem Fall ist der Kompilier Zeittyp des Ausdrucks dynamic , und die unten beschriebene Auflösung erfolgt zur Laufzeit mit dem Lauf Zeittyp der Operanden, die den Kompilier Zeittyp aufweisen dynamic .In this case the compile-time type of the expression is dynamic, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic.

Ein Vorgang des Formulars x && y oder x || y wird durch Anwenden der Überladungs Auflösung (binäre Operator Überladungs Auflösung) so verarbeitet, als ob der Vorgang geschrieben wurde x & y oder x | y .An operation of the form x && y or x || y is processed by applying overload resolution (Binary operator overload resolution) as if the operation was written x & y or x | y. Dies ergibt folgende Szenarien:Then,

Es ist nicht möglich, die bedingten logischen Operatoren direkt zu überladen.It is not possible to directly overload the conditional logical operators. Da die bedingten logischen Operatoren jedoch in Bezug auf die regulären logischen Operatoren ausgewertet werden, sind über Ladungen der regulären logischen Operatoren mit bestimmten Einschränkungen auch als über Ladungen der bedingten logischen Operatoren zu berücksichtigen.However, because the conditional logical operators are evaluated in terms of the regular logical operators, overloads of the regular logical operators are, with certain restrictions, also considered overloads of the conditional logical operators. Dies wird weiter unten unter Benutzerdefinierte bedingte logische Operatorenbeschrieben.This is described further in User-defined conditional logical operators.

Boolesche bedingte logische OperatorenBoolean conditional logical operators

Wenn die Operanden von && oder || vom Typ sind bool oder wenn es sich bei den Operanden um Typen handelt, die keinen anwendbaren operator & oder definieren operator | , aber implizite Konvertierungen in definieren, bool wird der Vorgang wie folgt verarbeitet:When the operands of && or || are of type bool, or when the operands are of types that do not define an applicable operator & or operator |, but do define implicit conversions to bool, the operation is processed as follows:

  • Der Vorgang x && y wird als ausgewertet x ? y : false .The operation x && y is evaluated as x ? y : false. Anders ausgedrückt, x wird zuerst ausgewertet und in den-Typ konvertiert bool .In other words, x is first evaluated and converted to type bool. Wenn den Wert hat, x true y wird ausgewertet und in den-Typ konvertiert bool , und dies wird das Ergebnis des Vorgangs.Then, if x is true, y is evaluated and converted to type bool, and this becomes the result of the operation. Andernfalls ist das Ergebnis des Vorgangs false .Otherwise, the result of the operation is false.
  • Der Vorgang x || y wird als ausgewertet x ? true : y .The operation x || y is evaluated as x ? true : y. Anders ausgedrückt, x wird zuerst ausgewertet und in den-Typ konvertiert bool .In other words, x is first evaluated and converted to type bool. Wenn den Wert x true hat, ist das Ergebnis des Vorgangs true .Then, if x is true, the result of the operation is true. Andernfalls y wird ausgewertet und in den-Typ konvertiert bool , und dies wird das Ergebnis des Vorgangs.Otherwise, y is evaluated and converted to type bool, and this becomes the result of the operation.

Benutzerdefinierte bedingte logische OperatorenUser-defined conditional logical operators

Wenn es sich bei den Operanden von && oder || um Typen handelt, die ein anwendbares benutzerdefiniertes oder deklarieren operator & operator | , müssen die beiden folgenden Optionen true sein, wobei T der Typ ist, in dem der ausgewählte Operator deklariert ist:When the operands of && or || are of types that declare an applicable user-defined operator & or operator |, both of the following must be true, where T is the type in which the selected operator is declared:

  • Der Rückgabetyp und der Typ jedes Parameters des ausgewählten Operators müssen sein T .The return type and the type of each parameter of the selected operator must be T. Mit anderen Worten, der-Operator muss das logische AND oder das logische OR von zwei Operanden vom Typ berechnen T , und muss ein Ergebnis vom Typ zurückgeben T .In other words, the operator must compute the logical AND or the logical OR of two operands of type T, and must return a result of type T.
  • T muss Deklarationen von operator true und enthalten operator false .T must contain declarations of operator true and operator false.

Ein Fehler bei der Bindungs Zeit tritt auf, wenn eine dieser Anforderungen nicht erfüllt wird.A binding-time error occurs if either of these requirements is not satisfied. Andernfalls wird der- && Vorgang oder der- || Vorgang ausgewertet, indem der benutzerdefinierte operator true oder operator false der ausgewählte benutzerdefinierte Operator kombiniert wird:Otherwise, the && or || operation is evaluated by combining the user-defined operator true or operator false with the selected user-defined operator:

  • Der Vorgang x && y wird als ausgewertet T.false(x) ? x : T.&(x, y) , wobei T.false(x) ein Aufruf von ist, der operator false in deklariert ist T , und T.&(x, y) ein Aufruf des ausgewählten operator & .The operation x && y is evaluated as T.false(x) ? x : T.&(x, y), where T.false(x) is an invocation of the operator false declared in T, and T.&(x, y) is an invocation of the selected operator &. Mit anderen Worten, x wird zuerst ausgewertet und für operator false das Ergebnis aufgerufen, um zu bestimmen, ob x definitiv false ist.In other words, x is first evaluated and operator false is invoked on the result to determine if x is definitely false. Wenn dann x definitiv false ist, ist das Ergebnis der Operation der Wert, der zuvor für berechnet wurde x .Then, if x is definitely false, the result of the operation is the value previously computed for x. Andernfalls y wird ausgewertet, und der ausgewählte operator & wird für den Wert aufgerufen, der zuvor für berechnet wurde, x und der Wert, der für berechnet wird, y um das Ergebnis des Vorgangs zu erhalten.Otherwise, y is evaluated, and the selected operator & is invoked on the value previously computed for x and the value computed for y to produce the result of the operation.
  • Der Vorgang x || y wird als ausgewertet T.true(x) ? x : T.|(x, y) , wobei T.true(x) ein Aufruf von ist, der operator true in deklariert ist T , und T.|(x,y) ein Aufruf des ausgewählten operator| .The operation x || y is evaluated as T.true(x) ? x : T.|(x, y), where T.true(x) is an invocation of the operator true declared in T, and T.|(x,y) is an invocation of the selected operator|. Mit anderen Worten, x wird zuerst ausgewertet und für operator true das Ergebnis aufgerufen, um zu bestimmen, ob x definitiv true ist.In other words, x is first evaluated and operator true is invoked on the result to determine if x is definitely true. Wenn dann x definitiv true ist, ist das Ergebnis der Operation der Wert, der zuvor für berechnet wurde x .Then, if x is definitely true, the result of the operation is the value previously computed for x. Andernfalls y wird ausgewertet, und der ausgewählte operator | wird für den Wert aufgerufen, der zuvor für berechnet wurde, x und der Wert, der für berechnet wird, y um das Ergebnis des Vorgangs zu erhalten.Otherwise, y is evaluated, and the selected operator | is invoked on the value previously computed for x and the value computed for y to produce the result of the operation.

Bei beiden Vorgängen wird der von angegebene Ausdruck x nur einmal ausgewertet, und der von angegebene Ausdruck y wird entweder nicht genau einmal ausgewertet oder ausgewertet.In either of these operations, the expression given by x is only evaluated once, and the expression given by y is either not evaluated or evaluated exactly once.

Ein Beispiel für einen Typ, der operator true und implementiert operator false , finden Sie unter Daten Bank boolescher Typ.For an example of a type that implements operator true and operator false, see Database boolean type.

The null coalescing operator (Der NULL-Sammeloperator)The null coalescing operator

Der- ?? Operator wird als NULL-Sammel Operator bezeichnet.The ?? operator is called the null coalescing operator.

null_coalescing_expression
    : conditional_or_expression
    | conditional_or_expression '??' null_coalescing_expression
    ;

Ein NULL-Sammel Ausdruck des Formulars a ?? b erfordert a , dass ein Typ oder Verweistyp ist, der NULL-Werte zulässt.A null coalescing expression of the form a ?? b requires a to be of a nullable type or reference type. Wenn a nicht NULL ist, ist das Ergebnis von a ?? b a . andernfalls ist das Ergebnis b .If a is non-null, the result of a ?? b is a; otherwise, the result is b. Der Vorgang wertet b nur aus, wenn a NULL ist.The operation evaluates b only if a is null.

Der NULL-Sammel Operator ist rechts assoziativ, was bedeutet, dass Vorgänge von rechts nach Links gruppiert werden.The null coalescing operator is right-associative, meaning that operations are grouped from right to left. Beispielsweise wird ein Ausdruck des Formulars a ?? b ?? c als ausgewertet a ?? (b ?? c) .For example, an expression of the form a ?? b ?? c is evaluated as a ?? (b ?? c). In der Regel gibt ein Ausdruck der Form E1 ?? E2 ?? ... ?? En den ersten der Operanden zurück, der nicht NULL ist, oder NULL, wenn alle Operanden NULL sind.In general terms, an expression of the form E1 ?? E2 ?? ... ?? En returns the first of the operands that is non-null, or null if all operands are null.

Der Typ des Ausdrucks a ?? b hängt davon ab, welche impliziten Konvertierungen für die Operanden verfügbar sind.The type of the expression a ?? b depends on which implicit conversions are available on the operands. In der angegebenen Reihenfolge ist der Typ a ?? b von A0 , A oder B , wobei A der Typ von a (bereitgestellt ist, der einen- a Typ aufweist), B der Typ von b (bereitgestellt mit b einem-Typ) und A0 der zugrunde liegende Typ von ist, A Wenn A ein Typ ist, der NULL-Werte zulässt, A andernfalls.In order of preference, the type of a ?? b is A0, A, or B, where A is the type of a (provided that a has a type), B is the type of b (provided that b has a type), and A0 is the underlying type of A if A is a nullable type, or A otherwise. Insbesondere a ?? b wird wie folgt verarbeitet:Specifically, a ?? b is processed as follows:

  • Wenn A vorhanden und kein Werte zulässt-Typ oder Verweistyp ist, tritt ein Kompilierzeitfehler auf.If A exists and is not a nullable type or a reference type, a compile-time error occurs.
  • Wenn b ein dynamischer Ausdruck ist, ist der Ergebnistyp dynamic .If b is a dynamic expression, the result type is dynamic. Zur Laufzeit a wird zuerst ausgewertet.At run-time, a is first evaluated. Wenn a nicht NULL ist, a wird in Dynamic konvertiert, und dies wird zum Ergebnis.If a is not null, a is converted to dynamic, and this becomes the result. Andernfalls b wird ausgewertet, und dies wird zum Ergebnis.Otherwise, b is evaluated, and this becomes the result.
  • Andernfalls A b A0 ist der Ergebnistyp, wenn vorhanden und ein Typ ist, der NULL-Werte zulässt, und eine implizite Konvertierung von in vorhanden ist A0 .Otherwise, if A exists and is a nullable type and an implicit conversion exists from b to A0, the result type is A0. Zur Laufzeit a wird zuerst ausgewertet.At run-time, a is first evaluated. Wenn a nicht NULL ist, a wird in den-Typ entpackt A0 , und dies wird zum Ergebnis.If a is not null, a is unwrapped to type A0, and this becomes the result. Andernfalls b wird ausgewertet und in A0 den-Typ konvertiert, sodass dies das Ergebnis ist.Otherwise, b is evaluated and converted to type A0, and this becomes the result.
  • Andernfalls A b A ist der Ergebnistyp, wenn vorhanden und eine implizite Konvertierung von in vorhanden ist A .Otherwise, if A exists and an implicit conversion exists from b to A, the result type is A. Zur Laufzeit a wird zuerst ausgewertet.At run-time, a is first evaluated. Wenn a nicht NULL ist, a wird das Ergebnis.If a is not null, a becomes the result. Andernfalls b wird ausgewertet und in A den-Typ konvertiert, sodass dies das Ergebnis ist.Otherwise, b is evaluated and converted to type A, and this becomes the result.
  • Andernfalls b B a B ist der Ergebnistyp, wenn einen-Typ aufweist und eine implizite Konvertierung von in vorhanden ist B .Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. Zur Laufzeit a wird zuerst ausgewertet.At run-time, a is first evaluated. Wenn a nicht NULL ist, a wird in den-Typ entpackt A0 (wenn A vorhanden und NULL-Werte zulässt) und in B den-Typ konvertiert werden. Dies wird zum Ergebnis.If a is not null, a is unwrapped to type A0 (if A exists and is nullable) and converted to type B, and this becomes the result. Andernfalls b wird ausgewertet und zum Ergebnis.Otherwise, b is evaluated and becomes the result.
  • Andernfalls a sind und nicht b kompatibel, und es tritt ein Kompilierzeitfehler auf.Otherwise, a and b are incompatible, and a compile-time error occurs.

Bedingter OperatorConditional operator

Der- ?: Operator wird als Bedingter Operator bezeichnet.The ?: operator is called the conditional operator. Es wird manchmal auch als ternärer Operator bezeichnet.It is at times also called the ternary operator.

conditional_expression
    : null_coalescing_expression
    | null_coalescing_expression '?' expression ':' expression
    ;

Ein bedingter Ausdruck des Formulars b ? x : y wertet die Bedingung zuerst aus b .A conditional expression of the form b ? x : y first evaluates the condition b. Wenn den Wert b true hat, x wird ausgewertet und zum Ergebnis des Vorgangs.Then, if b is true, x is evaluated and becomes the result of the operation. Andernfalls y wird ausgewertet und wird zum Ergebnis des Vorgangs.Otherwise, y is evaluated and becomes the result of the operation. Ein bedingter Ausdruck wertet nie sowohl x als auch aus y .A conditional expression never evaluates both x and y.

Der bedingte Operator ist rechts assoziativ, was bedeutet, dass Vorgänge von rechts nach Links gruppiert werden.The conditional operator is right-associative, meaning that operations are grouped from right to left. Beispielsweise wird ein Ausdruck des Formulars a ? b : c ? d : e als ausgewertet a ? b : (c ? d : e) .For example, an expression of the form a ? b : c ? d : e is evaluated as a ? b : (c ? d : e).

Der erste Operand des ?: Operators muss ein Ausdruck sein, der implizit in konvertiert werden kann bool , oder ein Ausdruck eines Typs, der implementiert operator true .The first operand of the ?: operator must be an expression that can be implicitly converted to bool, or an expression of a type that implements operator true. Wenn keine dieser Anforderungen erfüllt ist, tritt ein Kompilierzeitfehler auf.If neither of these requirements is satisfied, a compile-time error occurs.

Mit dem zweiten und dritten Operanden x y des ?: Operators wird der Typ des bedingten Ausdrucks gesteuert.The second and third operands, x and y, of the ?: operator control the type of the conditional expression.

  • Wenn den x Typ aufweist X und den y Typ hat, Y dannIf x has type X and y has type Y then
    • Wenn eine implizite Konvertierung (implizite Konvertierungen) von X in Y , aber nicht von Y in vorhanden ist X , dann Y ist der Typ des bedingten Ausdrucks.If an implicit conversion (Implicit conversions) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
    • Wenn eine implizite Konvertierung (implizite Konvertierungen) von Y in X , aber nicht von X in vorhanden ist Y , dann X ist der Typ des bedingten Ausdrucks.If an implicit conversion (Implicit conversions) exists from Y to X, but not from X to Y, then X is the type of the conditional expression.
    • Andernfalls kann kein Ausdruckstyp ermittelt werden, und es tritt ein Kompilierzeitfehler auf.Otherwise, no expression type can be determined, and a compile-time error occurs.
  • Wenn nur einer von x und y einen-Typ aufweist und sowohl x als auch y , von implizit in diesen Typ konvertiert werden können, ist dies der Typ des bedingten Ausdrucks.If only one of x and y has a type, and both x and y, of are implicitly convertible to that type, then that is the type of the conditional expression.
  • Andernfalls kann kein Ausdruckstyp ermittelt werden, und es tritt ein Kompilierzeitfehler auf.Otherwise, no expression type can be determined, and a compile-time error occurs.

Die Lauf Zeit Verarbeitung eines bedingten Ausdrucks der Form b ? x : y besteht aus den folgenden Schritten:The run-time processing of a conditional expression of the form b ? x : y consists of the following steps:

  • Zuerst b wird ausgewertet, und der bool Wert von b wird bestimmt:First, b is evaluated, and the bool value of b is determined:
    • Wenn eine implizite Konvertierung vom Typ von b in bool vorhanden ist, wird diese implizite Konvertierung durchgeführt, um einen bool Wert zu erhalten.If an implicit conversion from the type of b to bool exists, then this implicit conversion is performed to produce a bool value.
    • Andernfalls wird die operator true , die durch den Typ von definiert b wird, aufgerufen, um einen Wert zu erhalten bool .Otherwise, the operator true defined by the type of b is invoked to produce a bool value.
  • Wenn der bool durch den obigen Schritt erstellte Wert ist true , x wird ausgewertet und in den Typ des bedingten Ausdrucks konvertiert, und dies wird das Ergebnis des bedingten Ausdrucks.If the bool value produced by the step above is true, then x is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.
  • Andernfalls y wird ausgewertet und in den Typ des bedingten Ausdrucks konvertiert, und dies wird das Ergebnis des bedingten Ausdrucks.Otherwise, y is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.

Anonymous function expressions (Anonyme Funktionsausdrücke)Anonymous function expressions

Eine anonyme Funktion ist ein Ausdruck, der eine "Inline"-Methoden Definition darstellt.An anonymous function is an expression that represents an "in-line" method definition. Eine anonyme Funktion verfügt nicht über einen Wert oder einen Typ in und von sich selbst, kann jedoch in einen kompatiblen Delegaten oder Ausdrucks Strukturtyp konvertiert werden.An anonymous function does not have a value or type in and of itself, but is convertible to a compatible delegate or expression tree type. Die Auswertung einer anonymen Funktions Konvertierung hängt vom Zieltyp der Konvertierung ab: Wenn es sich um einen Delegattyp handelt, wird die Konvertierung zu einem Delegatwert ausgewertet, der auf die Methode verweist, die von der anonymen Funktion definiert wird.The evaluation of an anonymous function conversion depends on the target type of the conversion: If it is a delegate type, the conversion evaluates to a delegate value referencing the method which the anonymous function defines. Wenn es sich um einen Ausdrucks bauentyp handelt, wird die Konvertierung zu einer Ausdrucks Baumstruktur ausgewertet, die die Struktur der Methode als Objektstruktur darstellt.If it is an expression tree type, the conversion evaluates to an expression tree which represents the structure of the method as an object structure.

Aus historischen Gründen gibt es zwei syntaktische Varianten von anonymen Funktionen, nämlich lambda_expression s und anonymous_method_expression s.For historical reasons there are two syntactic flavors of anonymous functions, namely lambda_expression s and anonymous_method_expression s. Für fast alle Zwecke sind lambda_expression s präziser und ausdrucksstarker als anonymous_method_expression s, die für die Abwärtskompatibilität in der Sprache verbleiben.For almost all purposes, lambda_expression s are more concise and expressive than anonymous_method_expression s, which remain in the language for backwards compatibility.

lambda_expression
    : anonymous_function_signature '=>' anonymous_function_body
    ;

anonymous_method_expression
    : 'delegate' explicit_anonymous_function_signature? block
    ;

anonymous_function_signature
    : explicit_anonymous_function_signature
    | implicit_anonymous_function_signature
    ;

explicit_anonymous_function_signature
    : '(' explicit_anonymous_function_parameter_list? ')'
    ;

explicit_anonymous_function_parameter_list
    : explicit_anonymous_function_parameter (',' explicit_anonymous_function_parameter)*
    ;

explicit_anonymous_function_parameter
    : anonymous_function_parameter_modifier? type identifier
    ;

anonymous_function_parameter_modifier
    : 'ref'
    | 'out'
    ;

implicit_anonymous_function_signature
    : '(' implicit_anonymous_function_parameter_list? ')'
    | implicit_anonymous_function_parameter
    ;

implicit_anonymous_function_parameter_list
    : implicit_anonymous_function_parameter (',' implicit_anonymous_function_parameter)*
    ;

implicit_anonymous_function_parameter
    : identifier
    ;

anonymous_function_body
    : expression
    | block
    ;

Der Operator => verfügt über die gleiche Rangfolge wie die Zuweisung (=) und ist rechtsassoziativ.The => operator has the same precedence as assignment (=) and is right-associative.

Eine anonyme Funktion mit dem async -Modifizierer ist eine Async-Funktion und folgt den in Async-Funktionenbeschriebenen Regeln.An anonymous function with the async modifier is an async function and follows the rules described in Async functions.

Die Parameter einer anonymen Funktion in Form eines lambda_expression können explizit oder implizit eingegeben werden.The parameters of an anonymous function in the form of a lambda_expression can be explicitly or implicitly typed. In einer explizit typisierten Parameterliste wird der Typ jedes Parameters explizit angegeben.In an explicitly typed parameter list, the type of each parameter is explicitly stated. In einer implizit typisierten Parameterliste werden die Parametertypen aus dem Kontext abgeleitet, in dem die anonyme Funktion auftritt – insbesondere wenn die anonyme Funktion in einen kompatiblen Delegattyp oder Ausdrucks Strukturtyp konvertiert wird, stellt dieser Typ die Parametertypen (Anonyme Funktions Konvertierungen) bereit.In an implicitly typed parameter list, the types of the parameters are inferred from the context in which the anonymous function occurs—specifically, when the anonymous function is converted to a compatible delegate type or expression tree type, that type provides the parameter types (Anonymous function conversions).

In einer anonymen Funktion mit einem einzelnen, implizit typisierten Parameter können die Klammern in der Parameterliste weggelassen werden.In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. Anders ausgedrückt: eine anonyme Funktion der FormIn other words, an anonymous function of the form

( param ) => expr

kann abgekürzt werden zucan be abbreviated to

param => expr

Die Parameterliste einer anonymen Funktion in Form einer anonymous_method_expression ist optional.The parameter list of an anonymous function in the form of an anonymous_method_expression is optional. Wenn angegeben, müssen die Parameter explizit typisiert werden.If given, the parameters must be explicitly typed. Andernfalls kann die anonyme Funktion in einen Delegaten mit einer beliebigen Parameterliste konvertiert werden, die keine out Parameter enthält.If not, the anonymous function is convertible to a delegate with any parameter list not containing out parameters.

Ein Block Körper einer anonymen Funktion ist erreichbar (Endpunkte und Erreichbarkeit), es sei denn, die anonyme Funktion tritt innerhalb einer nicht erreichbaren Anweisung auf.A block body of an anonymous function is reachable (End points and reachability) unless the anonymous function occurs inside an unreachable statement.

Im folgenden finden Sie einige Beispiele für anonyme Funktionen:Some examples of anonymous functions follow below:

x => x + 1                              // Implicitly typed, expression body
x => { return x + 1; }                  // Implicitly typed, statement body
(int x) => x + 1                        // Explicitly typed, expression body
(int x) => { return x + 1; }            // Explicitly typed, statement body
(x, y) => x * y                         // Multiple parameters
() => Console.WriteLine()               // No parameters
async (t1,t2) => await t1 + await t2    // Async
delegate (int x) { return x + 1; }      // Anonymous method expression
delegate { return 1 + 1; }              // Parameter list omitted

Das Verhalten von lambda_expression s und anonymous_method_expression s ist mit Ausnahme der folgenden Punkte identisch:The behavior of lambda_expression s and anonymous_method_expression s is the same except for the following points:

  • anonymous_method_expression s erlauben, dass die Parameterliste vollständig ausgelassen wird, sodass die Konvertierungs Möglichkeit zum Delegieren von Typen von Wert Parametern ermöglicht wird.anonymous_method_expression s permit the parameter list to be omitted entirely, yielding convertibility to delegate types of any list of value parameters.
  • lambda_expression s zulassen, dass Parametertypen ausgelassen und abgeleitet werden, während anonymous_method_expression s Parametertypen explizit angeben müssen.lambda_expression s permit parameter types to be omitted and inferred whereas anonymous_method_expression s require parameter types to be explicitly stated.
  • Der Text eines lambda_expression kann ein Ausdruck oder ein Anweisungsblock sein, während der Text eines anonymous_method_expression ein Anweisungsblock sein muss.The body of a lambda_expression can be an expression or a statement block whereas the body of an anonymous_method_expression must be a statement block.
  • Nur lambda_expression s verfügen über Konvertierungen in kompatible Ausdrucks Baumstruktur Typen (Ausdrucks Baumstruktur Typen).Only lambda_expression s have conversions to compatible expression tree types (Expression tree types).

Anonyme Funktions SignaturenAnonymous function signatures

Der optionale anonymous_function_signature einer anonymen Funktion definiert die Namen und optional die Typen der formalen Parameter für die anonyme Funktion.The optional anonymous_function_signature of an anonymous function defines the names and optionally the types of the formal parameters for the anonymous function. Der Gültigkeitsbereich der Parameter der anonymen Funktion ist der anonymous_function_body.The scope of the parameters of the anonymous function is the anonymous_function_body. (Bereiche) In Verbindung mit der Parameterliste (falls angegeben) bildet der anonyme Methoden Text einen Deklarations Raum (Deklarationen).(Scopes) Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space (Declarations). Daher ist es ein Kompilierzeitfehler, wenn der Name eines Parameters der anonymen Funktion mit dem Namen einer lokalen Variablen, lokalen Konstante oder eines Parameters identisch ist, deren Bereich die anonymous_method_expression oder lambda_expression enthält.It is thus a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant or parameter whose scope includes the anonymous_method_expression or lambda_expression.

Wenn eine anonyme Funktion über eine explicit_anonymous_function_signature verfügt, ist der Satz kompatibler Delegattypen und Ausdrucks Baum Typen auf diejenigen beschränkt, die dieselben Parametertypen und Modifizierer in der gleichen Reihenfolge aufweisen.If an anonymous function has an explicit_anonymous_function_signature, then the set of compatible delegate types and expression tree types is restricted to those that have the same parameter types and modifiers in the same order. Im Gegensatz zu Methoden Gruppen Konvertierungen (Methoden Gruppen Konvertierungen) wird die kontra Varianz anonymer Funktionsparameter Typen nicht unterstützt.In contrast to method group conversions (Method group conversions), contra-variance of anonymous function parameter types is not supported. Wenn eine anonyme Funktion keine anonymous_function_signature hat, ist der Satz kompatibler Delegattypen und Ausdrucks Baum Typen auf diejenigen beschränkt, die keine Parameter haben out .If an anonymous function does not have an anonymous_function_signature, then the set of compatible delegate types and expression tree types is restricted to those that have no out parameters.

Beachten Sie, dass ein anonymous_function_signature keine Attribute oder ein Parameter Array enthalten kann.Note that an anonymous_function_signature cannot include attributes or a parameter array. Dennoch kann ein anonymous_function_signature mit einem Delegattyp kompatibel sein, dessen Parameterliste ein Parameter Array enthält.Nevertheless, an anonymous_function_signature may be compatible with a delegate type whose parameter list contains a parameter array.

Beachten Sie auch, dass bei der Konvertierung in einen Ausdrucks bauentyp, auch wenn diese kompatibel ist, während der Kompilierzeit (Ausdrucks Baumstruktur Typen) weiterhin Fehler auftreten können.Note also that conversion to an expression tree type, even if compatible, may still fail at compile-time (Expression tree types).

Anonyme Funktions TexteAnonymous function bodies

Der Text (Ausdruck oder Block) einer anonymen Funktion unterliegt den folgenden Regeln:The body (expression or block) of an anonymous function is subject to the following rules:

  • Wenn die anonyme Funktion eine Signatur enthält, sind die in der Signatur angegebenen Parameter im Textkörper verfügbar.If the anonymous function includes a signature, the parameters specified in the signature are available in the body. Wenn die anonyme Funktion keine Signatur aufweist, kann Sie in einen Delegattyp oder einen Ausdruckstyp mit Parametern (Anonyme Funktions Konvertierungen) konvertiert werden, aber auf die Parameter kann im Text nicht zugegriffen werden.If the anonymous function has no signature it can be converted to a delegate type or expression type having parameters (Anonymous function conversions), but the parameters cannot be accessed in the body.
  • Mit Ausnahme ref von-oder- out Parametern, die in der Signatur (sofern vorhanden) der nächstgelegenen einschließenden anonymen Funktion angegeben sind, ist dies ein Kompilierzeitfehler für den Text, um auf einen- ref oder- out Parameter zuzugreifenExcept for ref or out parameters specified in the signature (if any) of the nearest enclosing anonymous function, it is a compile-time error for the body to access a ref or out parameter.
  • Wenn der Typ von this ein Strukturtyp ist, ist dies ein Kompilierzeitfehler für den Text, auf den zugegriffen werden kann this .When the type of this is a struct type, it is a compile-time error for the body to access this. Dies gilt unabhängig davon, ob der Zugriff explizit (wie in this.x ) oder implizit ist (wie in, x wobei x ein Instanzmember der Struktur ist).This is true whether the access is explicit (as in this.x) or implicit (as in x where x is an instance member of the struct). Diese Regel verhindert einen solchen Zugriff und wirkt sich nicht darauf aus, ob die Member-Suche zu einem Member der Struktur führt.This rule simply prohibits such access and does not affect whether member lookup results in a member of the struct.
  • Der Text hat Zugriff auf die äußeren Variablen (äußere Variablen) der anonymen Funktion.The body has access to the outer variables (Outer variables) of the anonymous function. Der Zugriff auf eine äußere Variable verweist auf die Instanz der Variablen, die zum Zeitpunkt der Auswertung der lambda_expression oder anonymous_method_expression (Auswertung anonymer Funktions Ausdrücke) aktiv ist.Access of an outer variable will reference the instance of the variable that is active at the time the lambda_expression or anonymous_method_expression is evaluated (Evaluation of anonymous function expressions).
  • Es ist ein Kompilierzeitfehler, wenn der Text eine goto Anweisung, eine break Anweisung oder eine Anweisung enthält, continue deren Ziel außerhalb des Texts oder innerhalb des Texts einer enthaltenen anonymen Funktion liegt.It is a compile-time error for the body to contain a goto statement, break statement, or continue statement whose target is outside the body or within the body of a contained anonymous function.
  • Eine- return Anweisung im Text gibt die Steuerung von einem Aufruf der nächsten einschließenden anonymen Funktion zurück, nicht vom einschließenden Funktionsmember.A return statement in the body returns control from an invocation of the nearest enclosing anonymous function, not from the enclosing function member. Ein Ausdruck, der in einer- return Anweisung angegeben ist, muss implizit in den Rückgabetyp des Delegattyps oder Ausdrucks Struktur Typs konvertiert werden, in den die nächstgelegene einschließende lambda_expression oder anonymous_method_expression konvertiert wird (Anonyme Funktions Konvertierungen).An expression specified in a return statement must be implicitly convertible to the return type of the delegate type or expression tree type to which the nearest enclosing lambda_expression or anonymous_method_expression is converted (Anonymous function conversions).

Es ist explizit nicht angegeben, ob es eine Möglichkeit gibt, den Block einer anonymen Funktion auszuführen, außer durch Auswertung und Aufruf der lambda_expression oder anonymous_method_expression.It is explicitly unspecified whether there is any way to execute the block of an anonymous function other than through evaluation and invocation of the lambda_expression or anonymous_method_expression. Insbesondere kann der Compiler eine anonyme Funktion durch das Zusammenführen einer oder mehrerer benannter Methoden oder Typen implementieren.In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types. Die Namen dieser Elemente mit synthetischer kompilarverwendung müssen ein für die Compilerverwendung reserviertes Formular sein.The names of any such synthesized elements must be of a form reserved for compiler use.

Überladungs Auflösung und Anonyme FunktionenOverload resolution and anonymous functions

Anonyme Funktionen in einer Argumentliste sind an der Typrückschluss-und Überladungs Auflösung beteiligt.Anonymous functions in an argument list participate in type inference and overload resolution. Die genauen Regeln finden Sie unter Typrückschluss und Überladungs Auflösung .Please refer to Type inference and Overload resolution for the exact rules.

Das folgende Beispiel veranschaulicht die Auswirkung anonymer Funktionen auf die Überladungs Auflösung.The following example illustrates the effect of anonymous functions on overload resolution.

class ItemList<T>: List<T>
{
    public int Sum(Func<T,int> selector) {
        int sum = 0;
        foreach (T item in this) sum += selector(item);
        return sum;
    }

    public double Sum(Func<T,double> selector) {
        double sum = 0;
        foreach (T item in this) sum += selector(item);
        return sum;
    }
}

Die- ItemList<T> Klasse verfügt über zwei Sum Methoden.The ItemList<T> class has two Sum methods. Jede übernimmt ein- selector Argument, das den Wert aus einem Listenelement in Summen extrahiert.Each takes a selector argument, which extracts the value to sum over from a list item. Der extrahierte Wert kann entweder ein int oder ein sein, double und die resultierende Summe ist ebenfalls entweder ein int oder ein double .The extracted value can be either an int or a double and the resulting sum is likewise either an int or a double.

Die Sum Methoden können z. b. verwendet werden, um Summen aus einer Liste von Detail Zeilen in einer Reihenfolge zu berechnen.The Sum methods could for example be used to compute sums from a list of detail lines in an order.

class Detail
{
    public int UnitCount;
    public double UnitPrice;
    ...
}

void ComputeSums() {
    ItemList<Detail> orderDetails = GetOrderDetails(...);
    int totalUnits = orderDetails.Sum(d => d.UnitCount);
    double orderTotal = orderDetails.Sum(d => d.UnitPrice * d.UnitCount);
    ...
}

Beim ersten Aufruf von orderDetails.Sum Sum sind beide Methoden anwendbar, da die anonyme Funktion d => d. UnitCount sowohl mit als auch mit kompatibel Func<Detail,int> ist Func<Detail,double> .In the first invocation of orderDetails.Sum, both Sum methods are applicable because the anonymous function d => d. UnitCount is compatible with both Func<Detail,int> and Func<Detail,double>. Die Überladungs Auflösung wählt jedoch die erste Sum Methode aus, da die Konvertierung in Func<Detail,int> besser ist als die Konvertierung in Func<Detail,double> .However, overload resolution picks the first Sum method because the conversion to Func<Detail,int> is better than the conversion to Func<Detail,double>.

Beim zweiten Aufruf von orderDetails.Sum ist nur die zweite Sum Methode anwendbar, da die anonyme Funktion d => d.UnitPrice * d.UnitCount einen Wert vom Typ erzeugt double .In the second invocation of orderDetails.Sum, only the second Sum method is applicable because the anonymous function d => d.UnitPrice * d.UnitCount produces a value of type double. Daher wählt die Überladungs Auflösung die zweite Sum Methode für diesen Aufruf aus.Thus, overload resolution picks the second Sum method for that invocation.

Anonyme Funktionen und dynamische BindungAnonymous functions and dynamic binding

Eine anonyme Funktion kann kein Empfänger, Argument oder Operand eines dynamisch gebundenen Vorgangs sein.An anonymous function cannot be a receiver, argument or operand of a dynamically bound operation.

Äußere VariablenOuter variables

Alle lokalen Variablen, Wert Parameter oder Parameter Arrays, deren Bereich die lambda_expression oder anonymous_method_expression enthält, werden als äußere Variable der anonymen Funktion bezeichnet.Any local variable, value parameter, or parameter array whose scope includes the lambda_expression or anonymous_method_expression is called an outer variable of the anonymous function. In einem Instanzfunktionsmember einer Klasse this wird der Wert als Wert Parameter betrachtet und ist eine äußere Variable einer beliebigen anonymen Funktion, die im Funktionsmember enthalten ist.In an instance function member of a class, the this value is considered a value parameter and is an outer variable of any anonymous function contained within the function member.

Erfasste äußere VariablenCaptured outer variables

Wenn auf eine äußere Variable durch eine anonyme Funktion verwiesen wird, wird die äußere Variable als von der anonymen Funktion aufgezeichnet .When an outer variable is referenced by an anonymous function, the outer variable is said to have been captured by the anonymous function. Normalerweise ist die Lebensdauer einer lokalen Variable auf die Ausführung des Blocks oder der Anweisung beschränkt, mit der Sie verknüpft ist (lokale Variablen).Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated (Local variables). Die Lebensdauer einer erfassten äußeren Variable wird jedoch mindestens so lange verlängert, bis der Delegat oder die Ausdrucks Struktur, der aus der anonymen Funktion erstellt wurde, für Garbage Collection qualifiziert wird.However, the lifetime of a captured outer variable is extended at least until the delegate or expression tree created from the anonymous function becomes eligible for garbage collection.

Im BeispielIn the example

using System;

delegate int D();

class Test
{
    static D F() {
        int x = 0;
        D result = () => ++x;
        return result;
    }

    static void Main() {
        D d = F();
        Console.WriteLine(d());
        Console.WriteLine(d());
        Console.WriteLine(d());
    }
}

die lokale Variable x wird von der anonymen Funktion aufgezeichnet, und die Lebensdauer von x wird mindestens so lange verlängert, bis der Delegat, der von zurückgegeben wird, F für Garbage Collection qualifiziert ist (was bis zum Ende des Programms nicht erfolgt).the local variable x is captured by the anonymous function, and the lifetime of x is extended at least until the delegate returned from F becomes eligible for garbage collection (which doesn't happen until the very end of the program). Da jeder Aufruf der anonymen Funktion auf derselben Instanz von ausgeführt wird x , lautet die Ausgabe des Beispiels wie folgt:Since each invocation of the anonymous function operates on the same instance of x, the output of the example is:

1
2
3

Wenn eine lokale Variable oder ein value-Parameter von einer anonymen Funktion aufgezeichnet wird, wird die lokale Variable oder der Parameter nicht mehr als eine festgelegte Variable (fest-und verschiebbare Variablen) betrachtet, sondern als eine verschiebbare Variable angesehen.When a local variable or a value parameter is captured by an anonymous function, the local variable or parameter is no longer considered to be a fixed variable (Fixed and moveable variables), but is instead considered to be a moveable variable. Folglich unsafe muss jeglicher Code, der die Adresse einer erfassten äußeren Variablen annimmt, zuerst die- fixed Anweisung verwenden, um die Variable zu korrigieren.Thus any unsafe code that takes the address of a captured outer variable must first use the fixed statement to fix the variable.

Beachten Sie, dass im Gegensatz zu einer nicht erfassten Variablen eine aufgezeichnete lokale Variable gleichzeitig für mehrere Ausführungs Threads verfügbar gemacht werden kann.Note that unlike an uncaptured variable, a captured local variable can be simultaneously exposed to multiple threads of execution.

Instanziierung von lokalen VariablenInstantiation of local variables

Eine lokale Variable wird als instanziiert betrachtet, wenn die Ausführung in den Gültigkeitsbereich der Variablen eintritt.A local variable is considered to be instantiated when execution enters the scope of the variable. Wenn z. b. die folgende Methode aufgerufen wird, wird die lokale Variable x dreimal instanziiert und initialisiert – einmal für jede Iterationen der Schleife.For example, when the following method is invoked, the local variable x is instantiated and initialized three times—once for each iteration of the loop.

static void F() {
    for (int i = 0; i < 3; i++) {
        int x = i * 2 + 1;
        ...
    }
}

Das Verschieben der Deklaration von x außerhalb der Schleife führt jedoch zu einer einzelnen Instanziierung von x :However, moving the declaration of x outside the loop results in a single instantiation of x:

static void F() {
    int x;
    for (int i = 0; i < 3; i++) {
        x = i * 2 + 1;
        ...
    }
}

Bei nicht Erfassung kann nicht genau beachtet werden, wie oft eine lokale Variable instanziiert wird – da die Lebensdauer der Instanziierungen disjunkt ist, kann jede Instanziierung einfach denselben Speicherort verwenden.When not captured, there is no way to observe exactly how often a local variable is instantiated—because the lifetimes of the instantiations are disjoint, it is possible for each instantiation to simply use the same storage location. Wenn eine anonyme Funktion jedoch eine lokale Variable erfasst, werden die Auswirkungen der Instanziierung offensichtlich.However, when an anonymous function captures a local variable, the effects of instantiation become apparent.

Das BeispielThe example

using System;

delegate void D();

class Test
{
    static D[] F() {
        D[] result = new D[3];
        for (int i = 0; i < 3; i++) {
            int x = i * 2 + 1;
            result[i] = () => { Console.WriteLine(x); };
        }
        return result;
    }

    static void Main() {
        foreach (D d in F()) d();
    }
}

erzeugt die Ausgabe:produces the output:

1
3
5

Wenn jedoch die Deklaration von x außerhalb der Schleife verschoben wird:However, when the declaration of x is moved outside the loop:

static D[] F() {
    D[] result = new D[3];
    int x;
    for (int i = 0; i < 3; i++) {
        x = i * 2 + 1;
        result[i] = () => { Console.WriteLine(x); };
    }
    return result;
}

die Ausgabe lautet:the output is:

5
5
5

Wenn eine for-Schleife eine Iterations Variable deklariert, wird die Variable selbst als außerhalb der Schleife deklariert.If a for-loop declares an iteration variable, that variable itself is considered to be declared outside of the loop. Wenn das Beispiel so geändert wird, dass die Iterations Variable selbst aufgezeichnet wird:Thus, if the example is changed to capture the iteration variable itself:

static D[] F() {
    D[] result = new D[3];
    for (int i = 0; i < 3; i++) {
        result[i] = () => { Console.WriteLine(i); };
    }
    return result;
}

Es wird nur eine Instanz der Iterations Variablen aufgezeichnet, die die Ausgabe erzeugt:only one instance of the iteration variable is captured, which produces the output:

3
3
3

Es ist möglich, dass anonyme Funktions Delegaten einige erfasste Variablen freigeben, aber über separate Instanzen anderer Instanzen verfügen.It is possible for anonymous function delegates to share some captured variables yet have separate instances of others. Wenn beispielsweise F in geändert wird.For example, if F is changed to

static D[] F() {
    D[] result = new D[3];
    int x = 0;
    for (int i = 0; i < 3; i++) {
        int y = 0;
        result[i] = () => { Console.WriteLine("{0} {1}", ++x, ++y); };
    }
    return result;
}

die drei Delegaten erfassen dieselbe Instanz von x , aber separate Instanzen von y , und die Ausgabe lautet:the three delegates capture the same instance of x but separate instances of y, and the output is:

1 1
2 1
3 1

Separate anonyme Funktionen können dieselbe Instanz einer äußeren Variablen erfassen.Separate anonymous functions can capture the same instance of an outer variable. Im Beispiel:In the example:

using System;

delegate void Setter(int value);

delegate int Getter();

class Test
{
    static void Main() {
        int x = 0;
        Setter s = (int value) => { x = value; };
        Getter g = () => { return x; };
        s(5);
        Console.WriteLine(g());
        s(10);
        Console.WriteLine(g());
    }
}

die beiden anonymen Funktionen erfassen dieselbe Instanz der lokalen Variablen x und können daher über diese Variable kommunizieren.the two anonymous functions capture the same instance of the local variable x, and they can thus "communicate" through that variable. Die Ausgabe des Beispiels lautet wie folgt:The output of the example is:

5
10

Auswertung anonymer Funktions AusdrückeEvaluation of anonymous function expressions

Eine anonyme Funktion F muss immer in einen Delegattyp D oder einen Ausdrucks bauentyp konvertiert werden E , entweder direkt oder durch die Ausführung eines Ausdrucks zum Erstellen eines new D(F) Delegaten.An anonymous function F must always be converted to a delegate type D or an expression tree type E, either directly or through the execution of a delegate creation expression new D(F). Diese Konvertierung bestimmt das Ergebnis der anonymen Funktion, wie in Anonyme Funktions Konvertierungenbeschrieben.This conversion determines the result of the anonymous function, as described in Anonymous function conversions.

AbfrageausdrückeQuery expressions

Abfrage Ausdrücke bieten eine sprach integrierte Syntax für Abfragen, die relationalen und hierarchischen Abfrage Sprachen wie SQL und XQuery ähneln.Query expressions provide a language integrated syntax for queries that is similar to relational and hierarchical query languages such as SQL and XQuery.

query_expression
    : from_clause query_body
    ;

from_clause
    : 'from' type? identifier 'in' expression
    ;

query_body
    : query_body_clauses? select_or_group_clause query_continuation?
    ;

query_body_clauses
    : query_body_clause
    | query_body_clauses query_body_clause
    ;

query_body_clause
    : from_clause
    | let_clause
    | where_clause
    | join_clause
    | join_into_clause
    | orderby_clause
    ;

let_clause
    : 'let' identifier '=' expression
    ;

where_clause
    : 'where' boolean_expression
    ;

join_clause
    : 'join' type? identifier 'in' expression 'on' expression 'equals' expression
    ;

join_into_clause
    : 'join' type? identifier 'in' expression 'on' expression 'equals' expression 'into' identifier
    ;

orderby_clause
    : 'orderby' orderings
    ;

orderings
    : ordering (',' ordering)*
    ;

ordering
    : expression ordering_direction?
    ;

ordering_direction
    : 'ascending'
    | 'descending'
    ;

select_or_group_clause
    : select_clause
    | group_clause
    ;

select_clause
    : 'select' expression
    ;

group_clause
    : 'group' expression 'by' expression
    ;

query_continuation
    : 'into' identifier query_body
    ;

Ein Abfrage Ausdruck beginnt mit einer from -Klausel und endet mit einer- select oder- group Klausel.A query expression begins with a from clause and ends with either a select or group clause. Auf die Initial- from Klausel können NULL oder mehr from Klauseln, let , where oder join folgen orderby .The initial from clause can be followed by zero or more from, let, where, join or orderby clauses. Jede from Klausel ist ein Generator, der eine *Range-Variable _ einführt, in der die Elemente einer _ -Sequenz * liegen.Each from clause is a generator introducing a range variable _ which ranges over the elements of a _sequence**. Jede let Klausel führt eine Bereichs Variable ein, die einen Wert darstellt, der mithilfe vorheriger Bereichs Variablen berechnet wurde.Each let clause introduces a range variable representing a value computed by means of previous range variables. Jede- where Klausel ist ein Filter, der Elemente aus dem Ergebnis ausschließt.Each where clause is a filter that excludes items from the result. Jede join Klausel vergleicht die angegebenen Schlüssel der Quell Sequenz mit Schlüsseln einer anderen Sequenz und gibt passende Paare aus.Each join clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. Jede- orderby Klausel ordnet Elemente gemäß den angegebenen Kriterien neu an. Die abschließende- select oder- group Klausel gibt die Form des Ergebnisses in Bezug auf die Bereichs Variablen an.Each orderby clause reorders items according to specified criteria.The final select or group clause specifies the shape of the result in terms of the range variables. Zum Schluss kann eine- into Klausel verwendet werden, um Abfragen zu "Splice" zu verwenden, indem die Ergebnisse einer Abfrage als Generator in einer nachfolgenden Abfrage behandelt werden.Finally, an into clause can be used to "splice" queries by treating the results of one query as a generator in a subsequent query.

Mehrdeutigkeiten in Abfrage AusdrückenAmbiguities in query expressions

Abfrage Ausdrücke enthalten eine Reihe von "Kontext Schlüsselwörtern", d. h. Bezeichner, die in einem bestimmten Kontext eine besondere Bedeutung haben.Query expressions contain a number of "contextual keywords", i.e., identifiers that have special meaning in a given context. Dabei handelt es sich insbesondere um from , where , join , on , equals , into , let , orderby , ascending , descending , select group und by .Specifically these are from, where, join, on, equals, into, let, orderby, ascending, descending, select, group and by. Um Mehrdeutigkeiten in Abfrage Ausdrücken zu vermeiden, die durch die gemischte Verwendung dieser Bezeichner als Schlüsselwörter oder einfache Namen verursacht werden, werden diese Bezeichner als Schlüsselwörter betrachtet, wenn Sie an einer beliebigen Stelle innerhalb eines Abfrage Ausdrucks auftreten.In order to avoid ambiguities in query expressions caused by mixed use of these identifiers as keywords or simple names, these identifiers are considered keywords when occurring anywhere within a query expression.

Zu diesem Zweck ist ein Abfrage Ausdruck ein beliebiger Ausdruck, der mit " from identifier " gefolgt von einem beliebigen Token mit Ausnahme von "" ; , " = " oder " , " beginnt.For this purpose, a query expression is any expression that starts with "from identifier" followed by any token except ";", "=" or ",".

Um diese Wörter als Bezeichner innerhalb eines Abfrage Ausdrucks zu verwenden, kann Ihnen "" (Bezeichner) vorangestellt werden @ .In order to use these words as identifiers within a query expression, they can be prefixed with "@" (Identifiers).

Abfrage Ausdrucks ÜbersetzungQuery expression translation

In der Programmiersprache c# ist die Ausführungs Semantik von Abfrage Ausdrücken nicht angegeben.The C# language does not specify the execution semantics of query expressions. Stattdessen werden Abfrage Ausdrücke in Aufrufe von Methoden übersetzt, die dem Abfrage Ausdrucksmuster (dem Abfrage Ausdrucksmuster) entsprechen.Rather, query expressions are translated into invocations of methods that adhere to the query expression pattern (The query expression pattern). Abfrage Ausdrücke werden insbesondere in Aufrufe von Methoden mit den Namen Where , Select , SelectMany , Join , GroupJoin , OrderBy , OrderByDescending , ThenBy , ThenByDescending , und übersetzt GroupBy Cast . Diese Methoden verfügen über bestimmte Signaturen und Ergebnistypen, wie im Abfrage Ausdrucksmusterbeschrieben.Specifically, query expressions are translated into invocations of methods named Where, Select, SelectMany, Join, GroupJoin, OrderBy, OrderByDescending, ThenBy, ThenByDescending, GroupBy, and Cast.These methods are expected to have particular signatures and result types, as described in The query expression pattern. Diese Methoden können Instanzmethoden des Objekts sein, das abgefragt wird, oder Erweiterungs Methoden, die sich außerhalb des Objekts befinden, und Sie implementieren die tatsächliche Ausführung der Abfrage.These methods can be instance methods of the object being queried or extension methods that are external to the object, and they implement the actual execution of the query.

Die Übersetzung von Abfrage Ausdrücken in Methodenaufrufe ist eine syntaktische Zuordnung, die vor der Durchführung einer Typbindung oder Überladungs Auflösung auftritt.The translation from query expressions to method invocations is a syntactic mapping that occurs before any type binding or overload resolution has been performed. Es ist garantiert, dass die Übersetzung syntaktisch korrekt ist, aber es wird nicht garantiert, dass semantisch korrekter c#-Code erzeugt wird.The translation is guaranteed to be syntactically correct, but it is not guaranteed to produce semantically correct C# code. Nach der Übersetzung von Abfrage Ausdrücken werden die resultierenden Methodenaufrufe als reguläre Methodenaufrufe verarbeitet. Dies kann wiederum zu Fehlern führen, z. b. wenn die Methoden nicht vorhanden sind, wenn Argumente falsche Typen aufweisen oder wenn die Methoden generisch sind und der Typrückschluss fehlschlägt.Following translation of query expressions, the resulting method invocations are processed as regular method invocations, and this may in turn uncover errors, for example if the methods do not exist, if arguments have wrong types, or if the methods are generic and type inference fails.

Ein Abfrage Ausdruck wird durch wiederholtes Anwenden der folgenden Übersetzungen verarbeitet, bis keine weiteren Reduzierungen möglich sind.A query expression is processed by repeatedly applying the following translations until no further reductions are possible. Die Übersetzungen werden in der Reihenfolge der Anwendung aufgelistet: in jedem Abschnitt wird davon ausgegangen, dass die Übersetzungen in den vorangehenden Abschnitten umfassend ausgeführt wurden, und sobald Sie aufgebraucht sind, wird ein Abschnitt bei der Verarbeitung desselben Abfrage Ausdrucks nicht mehr untersucht.The translations are listed in order of application: each section assumes that the translations in the preceding sections have been performed exhaustively, and once exhausted, a section will not later be revisited in the processing of the same query expression.

Die Zuweisung zu Bereichs Variablen ist in Abfrage Ausdrücken nicht zulässig.Assignment to range variables is not allowed in query expressions. Eine c#-Implementierung darf diese Einschränkung jedoch nicht immer erzwingen, da dies möglicherweise manchmal nicht mit dem hier dargestellten syntaktische Translation-Schema möglich ist.However a C# implementation is permitted to not always enforce this restriction, since this may sometimes not be possible with the syntactic translation scheme presented here.

Bestimmte Übersetzungen fügen Bereichs Variablen mit transparenten Bezeichner ein, die von angegeben werden * .Certain translations inject range variables with transparent identifiers denoted by *. Die besonderen Eigenschaften von transparenten bezeichmern werden in transparenten bezeichmernweiter erläutert.The special properties of transparent identifiers are discussed further in Transparent identifiers.

SELECT-und GroupBy-Klauseln mit FortsetzungenSelect and groupby clauses with continuations

Ein Abfrage Ausdruck mit einer FortsetzungA query expression with a continuation

from ... into x ...

wird übersetzt inis translated into

from x in ( from ... ) ...

Bei den Übersetzungen in den folgenden Abschnitten wird davon ausgegangen, dass Abfragen keine into Fortsetzungen aufweisen.The translations in the following sections assume that queries have no into continuations.

Das BeispielThe example

from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }

wird übersetzt inis translated into

from g in
    from c in customers
    group c by c.Country
select new { Country = g.Key, CustCount = g.Count() }

die letzte Übersetzung, von derthe final translation of which is

customers.
GroupBy(c => c.Country).
Select(g => new { Country = g.Key, CustCount = g.Count() })

Explizite Bereichs Variablen TypenExplicit range variable types

Eine from Klausel, die explizit einen Bereichs Variablentyp angibt.A from clause that explicitly specifies a range variable type

from T x in e

wird übersetzt inis translated into

from x in ( e ) . Cast < T > ( )

Eine join Klausel, die explizit einen Bereichs Variablentyp angibt.A join clause that explicitly specifies a range variable type

join T x in e on k1 equals k2

wird übersetzt inis translated into

join x in ( e ) . Cast < T > ( ) on k1 equals k2

Bei den Übersetzungen in den folgenden Abschnitten wird davon ausgegangen, dass Abfragen keine expliziten Bereichs Variablen Typen aufweisen.The translations in the following sections assume that queries have no explicit range variable types.

Das BeispielThe example

from Customer c in customers
where c.City == "London"
select c

wird übersetzt inis translated into

from c in customers.Cast<Customer>()
where c.City == "London"
select c

die letzte Übersetzung, von derthe final translation of which is

customers.
Cast<Customer>().
Where(c => c.City == "London")

Explizite Bereichs Variablen Typen eignen sich zum Abfragen von Auflistungen, die die nicht generische- IEnumerable Schnittstelle implementieren, nicht jedoch die generische- IEnumerable<T> Schnittstelle.Explicit range variable types are useful for querying collections that implement the non-generic IEnumerable interface, but not the generic IEnumerable<T> interface. Im obigen Beispiel wäre dies der Fall, wenn customers vom Typ wäre ArrayList .In the example above, this would be the case if customers were of type ArrayList.

Degenerierte Abfrage AusdrückeDegenerate query expressions

Ein Abfrage Ausdruck der FormA query expression of the form

from x in e select x

wird übersetzt inis translated into

( e ) . Select ( x => x )

Das BeispielThe example

from c in customers
select c

wird übersetzt inis translated into

customers.Select(c => c)

Ein degenerierter Abfrage Ausdruck ist ein Ausdruck, der die Elemente der Quelle trivial auswählt.A degenerate query expression is one that trivially selects the elements of the source. In einer späteren Phase der Übersetzung werden degenerierte Abfragen entfernt, die durch andere Übersetzungsschritte eingeführt wurden, indem Sie durch ihre Quelle ersetzt werden.A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. Es ist jedoch wichtig zu gewährleisten, dass das Ergebnis eines Abfrage Ausdrucks nie das Quell Objekt selbst ist, da dadurch der Typ und die Identität der Quelle für den Client der Abfrage offengelegt werden.It is important however to ensure that the result of a query expression is never the source object itself, as that would reveal the type and identity of the source to the client of the query. Daher schützt dieser Schritt degenerierte Abfragen, die direkt im Quellcode geschrieben wurden, indem explizit Select für die Quelle aufgerufen wird.Therefore this step protects degenerate queries written directly in source code by explicitly calling Select on the source. Dann werden die Implementierer von Select und anderen Abfrage Operatoren übernommen, um sicherzustellen, dass diese Methoden nie das Quell Objekt selbst zurückgeben.It is then up to the implementers of Select and other query operators to ensure that these methods never return the source object itself.

From-, Let-, WHERE-, Join-und OrderBy-KlauselnFrom, let, where, join and orderby clauses

Ein Abfrage Ausdruck mit einer zweiten from Klausel gefolgt von einer- select Klausel.A query expression with a second from clause followed by a select clause

from x1 in e1
from x2 in e2
select v

wird übersetzt inis translated into

( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )

Ein Abfrage Ausdruck mit einer zweiten from Klausel, gefolgt von einem anderen Element als einer- select Klausel:A query expression with a second from clause followed by something other than a select clause:

from x1 in e1
from x2 in e2
...

wird übersetzt inis translated into

from * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } )
...

Ein Abfrage Ausdruck mit einer- let Klausel.A query expression with a let clause

from x in e
let y = f
...

wird übersetzt inis translated into

from * in ( e ) . Select ( x => new { x , y = f } )
...

Ein Abfrage Ausdruck mit einer- where Klausel.A query expression with a where clause

from x in e
where f
...

wird übersetzt inis translated into

from x in ( e ) . Where ( x => f )
...

Ein Abfrage Ausdruck mit einer- join Klausel ohne, into gefolgt von einer- select Klausel.A query expression with a join clause without an into followed by a select clause

from x1 in e1
join x2 in e2 on k1 equals k2
select v

wird übersetzt inis translated into

( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => v )

Ein Abfrage Ausdruck mit einer- join Klausel ohne, into gefolgt von einem anderen als einer- select Klausel.A query expression with a join clause without an into followed by something other than a select clause

from x1 in e1
join x2 in e2 on k1 equals k2
...

wird übersetzt inis translated into

from * in ( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })
...

Ein Abfrage Ausdruck mit einer- join Klausel mit einer, into gefolgt von einer- select Klausel.A query expression with a join clause with an into followed by a select clause

from x1 in e1
join x2 in e2 on k1 equals k2 into g
select v

wird übersetzt inis translated into

( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => v )

Ein Abfrage Ausdruck mit einer- join Klausel mit einem into gefolgt von einer- select Klausel.A query expression with a join clause with an into followed by something other than a select clause

from x1 in e1
join x2 in e2 on k1 equals k2 into g
...

wird übersetzt inis translated into

from * in ( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => new { x1 , g })
...

Ein Abfrage Ausdruck mit einer- orderby Klausel.A query expression with an orderby clause

from x in e
orderby k1 , k2 , ..., kn
...

wird übersetzt inis translated into

from x in ( e ) . 
OrderBy ( x => k1 ) . 
ThenBy ( x => k2 ) .
... .
ThenBy ( x => kn )
...

Wenn eine ORDER-Klausel einen descending Richtungsindikator angibt, wird stattdessen ein Aufruf von OrderByDescending oder ThenByDescending erzeugt.If an ordering clause specifies a descending direction indicator, an invocation of OrderByDescending or ThenByDescending is produced instead.

Bei den folgenden Übersetzungen wird davon ausgegangen, dass es keine let where join -, orderby -oder-Klauseln und nicht mehr als eine anfängliche- from Klausel in jedem Abfrage Ausdruck gibt.The following translations assume that there are no let, where, join or orderby clauses, and no more than the one initial from clause in each query expression.

Das BeispielThe example

from c in customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total }

wird übersetzt inis translated into

customers.
SelectMany(c => c.Orders,
     (c,o) => new { c.Name, o.OrderID, o.Total }
)

Das BeispielThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }

wird übersetzt inis translated into

from * in customers.
    SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }

die letzte Übersetzung, von derthe final translation of which is

customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(x => x.o.Total).
Select(x => new { x.c.Name, x.o.OrderID, x.o.Total })

dabei x ist ein vom Compiler generierter Bezeichner, der andernfalls unsichtbar ist und nicht zugänglich ist.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

Das BeispielThe example

from o in orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t }

wird übersetzt inis translated into

from * in orders.
    Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) })
where t >= 1000 
select new { o.OrderID, Total = t }

die letzte Übersetzung, von derthe final translation of which is

orders.
Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) }).
Where(x => x.t >= 1000).
Select(x => new { x.o.OrderID, Total = x.t })

dabei x ist ein vom Compiler generierter Bezeichner, der andernfalls unsichtbar ist und nicht zugänglich ist.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

Das BeispielThe example

from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }

wird übersetzt inis translated into

customers.Join(orders, c => c.CustomerID, o => o.CustomerID,
    (c, o) => new { c.Name, o.OrderDate, o.Total })

Das BeispielThe example

from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
let n = co.Count()
where n >= 10
select new { c.Name, OrderCount = n }

wird übersetzt inis translated into

from * in customers.
    GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
        (c, co) => new { c, co })
let n = co.Count()
where n >= 10 
select new { c.Name, OrderCount = n }

die letzte Übersetzung, von derthe final translation of which is

customers.
GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
    (c, co) => new { c, co }).
Select(x => new { x, n = x.co.Count() }).
Where(y => y.n >= 10).
Select(y => new { y.x.c.Name, OrderCount = y.n)

dabei x sind und vom y Compiler generierte Bezeichner, die ansonsten unsichtbar sind und nicht zugänglich sind.where x and y are compiler generated identifiers that are otherwise invisible and inaccessible.

Das BeispielThe example

from o in orders
orderby o.Customer.Name, o.Total descending
select o

hat die endgültige Übersetzunghas the final translation

orders.
OrderBy(o => o.Customer.Name).
ThenByDescending(o => o.Total)

Select-KlauselnSelect clauses

Ein Abfrage Ausdruck der FormA query expression of the form

from x in e select v

wird übersetzt inis translated into

( e ) . Select ( x => v )

mit der Ausnahme, dass v der Bezeichner x ist, ist die Übersetzung einfachexcept when v is the identifier x, the translation is simply

( e )

Beispiel:For example

from c in customers.Where(c => c.City == "London")
select c

wird einfach in übersetztis simply translated into

customers.Where(c => c.City == "London")

GroupBy-KlauselnGroupby clauses

Ein Abfrage Ausdruck der FormA query expression of the form

from x in e group v by k

wird übersetzt inis translated into

( e ) . GroupBy ( x => k , x => v )

außer wenn v der Bezeichner x ist, ist die Übersetzungexcept when v is the identifier x, the translation is

( e ) . GroupBy ( x => k )

Das BeispielThe example

from c in customers
group c.Name by c.Country

wird übersetzt inis translated into

customers.
GroupBy(c => c.Country, c => c.Name)

Transparente BezeichnerTransparent identifiers

Bestimmte Übersetzungen fügen Bereichs Variablen mit *transparenten Bezeichner _ ein, die von angegeben werden _ .Certain translations inject range variables with *transparent identifiers _ denoted by _. Transparente Bezeichner sind keine ordnungsgemäße Sprachfunktion. Sie sind nur als Zwischenschritt im Übersetzungsprozess des Abfrage Ausdrucks vorhanden.Transparent identifiers are not a proper language feature; they exist only as an intermediate step in the query expression translation process.

Wenn eine Abfrage Übersetzung einen transparenten Bezeichner einfügt, verbreiten weitere Übersetzungsschritte den transparenten Bezeichner an anonyme Funktionen und anonyme Objektinitialisierer.When a query translation injects a transparent identifier, further translation steps propagate the transparent identifier into anonymous functions and anonymous object initializers. In diesen Kontexten weisen transparente Bezeichner folgendes Verhalten auf:In those contexts, transparent identifiers have the following behavior:

  • Wenn ein transparenter Bezeichner als Parameter in einer anonymen Funktion auftritt, werden die Member des zugeordneten anonymen Typs automatisch im Gültigkeitsbereich des Texts der anonymen Funktion angezeigt.When a transparent identifier occurs as a parameter in an anonymous function, the members of the associated anonymous type are automatically in scope in the body of the anonymous function.
  • Wenn sich ein Element mit einem transparenten Bezeichner im Gültigkeitsbereich befindet, sind die Member dieses Members ebenfalls im Gültigkeitsbereich.When a member with a transparent identifier is in scope, the members of that member are in scope as well.
  • Wenn ein transparenter Bezeichner als Member-Deklarator in einem anonymen Objektinitialisierer auftritt, führt er einen Member mit einem transparenten Bezeichner ein.When a transparent identifier occurs as a member declarator in an anonymous object initializer, it introduces a member with a transparent identifier.
  • In den oben beschriebenen Übersetzungs Schritten werden transparente Bezeichner immer mit anonymen Typen eingeführt, mit dem Ziel, mehrere Bereichs Variablen als Member eines einzelnen Objekts zu erfassen.In the translation steps described above, transparent identifiers are always introduced together with anonymous types, with the intent of capturing multiple range variables as members of a single object. Eine Implementierung von c# darf einen anderen Mechanismus als anonyme Typen verwenden, um mehrere Bereichs Variablen zu gruppieren.An implementation of C# is permitted to use a different mechanism than anonymous types to group together multiple range variables. In den folgenden Übersetzungs Beispielen wird davon ausgegangen, dass anonyme Typen verwendet werden, und es wird gezeigt, wie transparente Bezeichner übersetzt werden können.The following translation examples assume that anonymous types are used, and show how transparent identifiers can be translated away.

Das BeispielThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.Total }

wird übersetzt inis translated into

from * in customers.
    SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.Total }

weiter übersetzt inwhich is further translated into

customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(* => o.Total).
Select(* => new { c.Name, o.Total })

, die beim Löschen transparenter Bezeichner entspricht.which, when transparent identifiers are erased, is equivalent to

customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(x => x.o.Total).
Select(x => new { x.c.Name, x.o.Total })

dabei x ist ein vom Compiler generierter Bezeichner, der andernfalls unsichtbar ist und nicht zugänglich ist.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

Das BeispielThe example

from c in customers
join o in orders on c.CustomerID equals o.CustomerID
join d in details on o.OrderID equals d.OrderID
join p in products on d.ProductID equals p.ProductID
select new { c.Name, o.OrderDate, p.ProductName }

wird übersetzt inis translated into

from * in customers.
    Join(orders, c => c.CustomerID, o => o.CustomerID, 
        (c, o) => new { c, o })
join d in details on o.OrderID equals d.OrderID
join p in products on d.ProductID equals p.ProductID
select new { c.Name, o.OrderDate, p.ProductName }

Dies wird weiter reduziert aufwhich is further reduced to

customers.
Join(orders, c => c.CustomerID, o => o.CustomerID, (c, o) => new { c, o }).
Join(details, * => o.OrderID, d => d.OrderID, (*, d) => new { *, d }).
Join(products, * => d.ProductID, p => p.ProductID, (*, p) => new { *, p }).
Select(* => new { c.Name, o.OrderDate, p.ProductName })

die letzte Übersetzung, von derthe final translation of which is

customers.
Join(orders, c => c.CustomerID, o => o.CustomerID,
    (c, o) => new { c, o }).
Join(details, x => x.o.OrderID, d => d.OrderID,
    (x, d) => new { x, d }).
Join(products, y => y.d.ProductID, p => p.ProductID,
    (y, p) => new { y, p }).
Select(z => new { z.y.x.c.Name, z.y.x.o.OrderDate, z.p.ProductName })

dabei x y sind, und vom Compiler generierte Bezeichner z , die andernfalls unsichtbar und nicht zugänglich sind.where x, y, and z are compiler generated identifiers that are otherwise invisible and inaccessible.

Das Abfrage AusdrucksmusterThe query expression pattern

Das Abfrage Ausdrucksmuster stellt ein Muster von Methoden dar, die von Typen implementiert werden können, um Abfrage Ausdrücke zu unterstützen.The Query expression pattern establishes a pattern of methods that types can implement to support query expressions. Da Abfrage Ausdrücke über eine syntaktische Zuordnung in Methodenaufrufe übersetzt werden, haben Typen bei der Implementierung des Abfrage Ausdrucks Musters eine beträchtliche Flexibilität.Because query expressions are translated to method invocations by means of a syntactic mapping, types have considerable flexibility in how they implement the query expression pattern. Beispielsweise können die Methoden des Musters als Instanzmethoden oder als Erweiterungs Methoden implementiert werden, da beide die gleiche Aufruf Syntax aufweisen und die Methoden Delegaten oder Ausdrucks Baumstrukturen anfordern können, da anonyme Funktionen in beides konvertierbar sind.For example, the methods of the pattern can be implemented as instance methods or as extension methods because the two have the same invocation syntax, and the methods can request delegates or expression trees because anonymous functions are convertible to both.

Die empfohlene Form eines generischen Typs C<T> , der das Abfrage Ausdrucksmuster unterstützt, ist unten dargestellt.The recommended shape of a generic type C<T> that supports the query expression pattern is shown below. Ein generischer Typ wird verwendet, um die richtigen Beziehungen zwischen Parameter-und Ergebnistypen zu veranschaulichen, aber es ist auch möglich, das Muster für nicht generische Typen zu implementieren.A generic type is used in order to illustrate the proper relationships between parameter and result types, but it is possible to implement the pattern for non-generic types as well.

delegate R Func<T1,R>(T1 arg1);

delegate R Func<T1,T2,R>(T1 arg1, T2 arg2);

class C
{
    public C<T> Cast<T>();
}

class C<T> : C
{
    public C<T> Where(Func<T,bool> predicate);

    public C<U> Select<U>(Func<T,U> selector);

    public C<V> SelectMany<U,V>(Func<T,C<U>> selector,
        Func<T,U,V> resultSelector);

    public C<V> Join<U,K,V>(C<U> inner, Func<T,K> outerKeySelector,
        Func<U,K> innerKeySelector, Func<T,U,V> resultSelector);

    public C<V> GroupJoin<U,K,V>(C<U> inner, Func<T,K> outerKeySelector,
        Func<U,K> innerKeySelector, Func<T,C<U>,V> resultSelector);

    public O<T> OrderBy<K>(Func<T,K> keySelector);

    public O<T> OrderByDescending<K>(Func<T,K> keySelector);

    public C<G<K,T>> GroupBy<K>(Func<T,K> keySelector);

    public C<G<K,E>> GroupBy<K,E>(Func<T,K> keySelector,
        Func<T,E> elementSelector);
}

class O<T> : C<T>
{
    public O<T> ThenBy<K>(Func<T,K> keySelector);

    public O<T> ThenByDescending<K>(Func<T,K> keySelector);
}

class G<K,T> : C<T>
{
    public K Key { get; }
}

Die oben genannten Methoden verwenden die generischen Delegattypen Func<T1,R> und Func<T1,T2,R> , aber Sie könnten auch andere Delegattypen von Delegaten oder Ausdrücken mit denselben Beziehungen in Parameter-und Ergebnistypen verwenden.The methods above use the generic delegate types Func<T1,R> and Func<T1,T2,R>, but they could equally well have used other delegate or expression tree types with the same relationships in parameter and result types.

Beachten Sie die empfohlene Beziehung zwischen C<T> und O<T> , wodurch sichergestellt wird, dass die ThenBy -Methode und die- ThenByDescending Methode nur für das Ergebnis eines oder verfügbar sind OrderBy OrderByDescending .Notice the recommended relationship between C<T> and O<T> which ensures that the ThenBy and ThenByDescending methods are available only on the result of an OrderBy or OrderByDescending. Beachten Sie auch die empfohlene Form des Ergebnisses von GroupBy --eine Sequenz von Sequenzen, wobei jede innere Sequenz über eine zusätzliche Key Eigenschaft verfügt.Also notice the recommended shape of the result of GroupBy -- a sequence of sequences, where each inner sequence has an additional Key property.

Der- System.Linq Namespace stellt eine Implementierung des Abfrage Operator Musters für jeden Typ bereit, der die- System.Collections.Generic.IEnumerable<T> Schnittstelle implementiert.The System.Linq namespace provides an implementation of the query operator pattern for any type that implements the System.Collections.Generic.IEnumerable<T> interface.

ZuweisungsoperatorenAssignment operators

Die Zuweisungs Operatoren weisen einer Variablen, einer Eigenschaft, einem Ereignis oder einem Indexer-Element einen neuen Wert zu.The assignment operators assign a new value to a variable, a property, an event, or an indexer element.

assignment
    : unary_expression assignment_operator expression
    ;

assignment_operator
    : '='
    | '+='
    | '-='
    | '*='
    | '/='
    | '%='
    | '&='
    | '|='
    | '^='
    | '<<='
    | right_shift_assignment
    ;

Der linke Operand einer Zuweisung muss ein Ausdruck sein, der als Variable, Eigenschaften Zugriff, Indexerzugriff oder Ereignis Zugriff klassifiziert ist.The left operand of an assignment must be an expression classified as a variable, a property access, an indexer access, or an event access.

Der- = Operator wird als einfacher Zuweisungs Operator bezeichnet.The = operator is called the simple assignment operator. Er weist den Wert des rechten Operanden der Variablen, der Eigenschaft oder dem Indexer-Element zu, die durch den linken Operanden angegeben werden.It assigns the value of the right operand to the variable, property, or indexer element given by the left operand. Der linke Operand des einfachen Zuweisungs Operators ist möglicherweise kein Ereignis Zugriff (außer wie in Feld ähnlichen Ereignissenbeschrieben).The left operand of the simple assignment operator may not be an event access (except as described in Field-like events). Der einfache Zuweisungs Operator wird unter einfache Zuweisungbeschrieben.The simple assignment operator is described in Simple assignment.

Die anderen Zuweisungs Operatoren als der- = Operator werden als Verbund Zuweisungs Operatoren bezeichnet.The assignment operators other than the = operator are called the compound assignment operators. Diese Operatoren führen den angegebenen Vorgang für die beiden Operanden aus und weisen dann den resultierenden Wert der Variablen, der Eigenschaft oder dem Indexer-Element zu, das durch den linken Operanden angegeben wird.These operators perform the indicated operation on the two operands, and then assign the resulting value to the variable, property, or indexer element given by the left operand. Die Verbund Zuweisungs Operatoren werden unter Verbund Zuweisungbeschrieben.The compound assignment operators are described in Compound assignment.

Die += -= Operatoren und mit einem Ereignis Zugriffs Ausdruck als Linker Operand werden als Ereignis Zuweisungs Operatoren bezeichnet.The += and -= operators with an event access expression as the left operand are called the event assignment operators. Kein anderer Zuweisungs Operator ist mit einem Ereignis Zugriff als Linker Operand gültig.No other assignment operator is valid with an event access as the left operand. Die Ereignis Zuweisungs Operatoren werden unter Ereignis Zuweisungbeschrieben.The event assignment operators are described in Event assignment.

Die Zuweisungs Operatoren sind rechts assoziativ, was bedeutet, dass Vorgänge von rechts nach Links gruppiert werden.The assignment operators are right-associative, meaning that operations are grouped from right to left. Beispielsweise wird ein Ausdruck des Formulars a = b = c als ausgewertet a = (b = c) .For example, an expression of the form a = b = c is evaluated as a = (b = c).

Einfache ZuweisungSimple assignment

Der- = Operator wird als einfacher Zuweisungs Operator bezeichnet.The = operator is called the simple assignment operator.

Wenn der linke Operand einer einfachen Zuweisung das Format E.P aufweist oder wenn E[Ei] E den Kompilier Zeittyp aufweist dynamic , wird die Zuweisung dynamisch gebunden (dynamische Bindung).If the left operand of a simple assignment is of the form E.P or E[Ei] where E has the compile-time type dynamic, then the assignment is dynamically bound (Dynamic binding). In diesem Fall ist der Kompilier Zeittyp des Zuweisungs Ausdrucks dynamic , und die unten beschriebene Auflösung erfolgt zur Laufzeit basierend auf dem Lauf Zeittyp von E .In this case the compile-time type of the assignment expression is dynamic, and the resolution described below will take place at run-time based on the run-time type of E.

In einer einfachen Zuweisung muss der rechte Operand ein Ausdruck sein, der implizit in den Typ des linken Operanden konvertiert werden kann.In a simple assignment, the right operand must be an expression that is implicitly convertible to the type of the left operand. Der-Vorgang weist den Wert des rechten Operanden der Variablen, der Eigenschaft oder dem Indexer-Element zu, die durch den linken Operanden angegeben werden.The operation assigns the value of the right operand to the variable, property, or indexer element given by the left operand.

Das Ergebnis eines einfachen Zuweisungs Ausdrucks ist der Wert, der dem linken Operanden zugewiesen wird.The result of a simple assignment expression is the value assigned to the left operand. Das Ergebnis hat denselben Typ wie der linke Operand und wird immer als Wert klassifiziert.The result has the same type as the left operand and is always classified as a value.

Wenn der linke Operand eine Eigenschaft oder ein Indexer-Zugriff ist, muss die Eigenschaft oder der Indexer über einen set Accessor verfügen.If the left operand is a property or indexer access, the property or indexer must have a set accessor. Wenn dies nicht der Fall ist, tritt ein Bindungs Zeitfehler auf.If this is not the case, a binding-time error occurs.

Die Lauf Zeit Verarbeitung einer einfachen Zuweisung des Formulars x = y besteht aus den folgenden Schritten:The run-time processing of a simple assignment of the form x = y consists of the following steps:

  • Wenn x als Variable klassifiziert ist:If x is classified as a variable:
    • x wird ausgewertet, um die Variable zu entwickeln.x is evaluated to produce the variable.
    • y wird ausgewertet und, falls erforderlich, durch eine implizite Konvertierung in den Typ von konvertiert x (implizite Konvertierungen).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • Wenn die von angegebene Variable x ein Array Element einer reference_type ist, wird eine Lauf Zeit Überprüfung durchgeführt, um sicherzustellen, dass der für berechnete Wert y mit der Array Instanz von kompatibel ist, bei der x es sich um ein Element handelt.If the variable given by x is an array element of a reference_type, a run-time check is performed to ensure that the value computed for y is compatible with the array instance of which x is an element. Die Überprüfung y ist erfolgreich, wenn ist null , oder wenn eine implizite Verweis Konvertierung (implizite Verweis Konvertierungen) aus dem tatsächlichen Typ der Instanz vorhanden ist, auf die von verwiesen wird, y auf den tatsächlichen Elementtyp der Array Instanz, die enthält x .The check succeeds if y is null, or if an implicit reference conversion (Implicit reference conversions) exists from the actual type of the instance referenced by y to the actual element type of the array instance containing x. Andernfalls wird eine System.ArrayTypeMismatchException ausgelöst.Otherwise, a System.ArrayTypeMismatchException is thrown.
    • Der Wert, der sich aus der Auswertung und Konvertierung von ergibt, y wird an dem Speicherort gespeichert, der durch die Auswertung von angegeben wird x .The value resulting from the evaluation and conversion of y is stored into the location given by the evaluation of x.
  • Wenn x als Eigenschaft oder Indexer-Zugriff klassifiziert ist:If x is classified as a property or indexer access:
    • Der Instanzausdruck (wenn x nicht ist static ), und die Argumentliste (wenn x ein Indexer-Zugriff ist), die zugeordnet ist x , wird ausgewertet, und die Ergebnisse werden im nachfolgenden accessoraufruf verwendet set .The instance expression (if x is not static) and the argument list (if x is an indexer access) associated with x are evaluated, and the results are used in the subsequent set accessor invocation.
    • y wird ausgewertet und, falls erforderlich, durch eine implizite Konvertierung in den Typ von konvertiert x (implizite Konvertierungen).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • Der- set Accessor von x wird mit dem Wert aufgerufen, der für y als sein-Argument berechnet wird value .The set accessor of x is invoked with the value computed for y as its value argument.

Die Array-Co-Varianz Regeln (Array-Kovarianz) erlauben, dass ein Wert eines Arraytyps A[] ein Verweis auf eine Instanz eines Arraytyps B[] ist, vorausgesetzt, dass eine implizite Verweis Konvertierung von in vorhanden ist B A .The array co-variance rules (Array covariance) permit a value of an array type A[] to be a reference to an instance of an array type B[], provided an implicit reference conversion exists from B to A. Aufgrund dieser Regeln erfordert die Zuweisung zu einem Array Element einer reference_type eine Lauf Zeit Überprüfung, um sicherzustellen, dass der zugewiesene Wert mit der Array Instanz kompatibel ist.Because of these rules, assignment to an array element of a reference_type requires a run-time check to ensure that the value being assigned is compatible with the array instance. Im BeispielIn the example

string[] sa = new string[10];
object[] oa = sa;

oa[0] = null;               // Ok
oa[1] = "Hello";            // Ok
oa[2] = new ArrayList();    // ArrayTypeMismatchException

die letzte Zuweisung bewirkt System.ArrayTypeMismatchException , dass eine ausgelöst wird, da eine Instanz von ArrayList nicht in einem Element von gespeichert werden kann string[] .the last assignment causes a System.ArrayTypeMismatchException to be thrown because an instance of ArrayList cannot be stored in an element of a string[].

Wenn eine in einem struct_type deklarierte Eigenschaft oder ein Indexer das Ziel einer Zuweisung ist, muss der Instanzausdruck, der der Eigenschaft oder dem Indexer-Zugriff zugeordnet ist, als Variable klassifiziert werden.When a property or indexer declared in a struct_type is the target of an assignment, the instance expression associated with the property or indexer access must be classified as a variable. Wenn der Instanzausdruck als Wert klassifiziert wird, tritt ein Fehler bei der Bindung auf.If the instance expression is classified as a value, a binding-time error occurs. Aufgrund des Mitglieds Zugriffsgilt die gleiche Regel auch für Felder.Because of Member access, the same rule also applies to fields.

Bei den Deklarationen:Given the declarations:

struct Point
{
    int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int X {
        get { return x; }
        set { x = value; }
    }

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

struct Rectangle
{
    Point a, b;

    public Rectangle(Point a, Point b) {
        this.a = a;
        this.b = b;
    }

    public Point A {
        get { return a; }
        set { a = value; }
    }

    public Point B {
        get { return b; }
        set { b = value; }
    }
}

im Beispielin the example

Point p = new Point();
p.X = 100;
p.Y = 100;
Rectangle r = new Rectangle();
r.A = new Point(10, 10);
r.B = p;

die Zuweisungen für p.X , p.Y , r.A und r.B sind zulässig, da p und r Variablen sind.the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. Im BeispielHowever, in the example

Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;

die Zuweisungen sind ungültig, da r.A und r.B keine Variablen sind.the assignments are all invalid, since r.A and r.B are not variables.

VerbundzuweisungCompound assignment

Wenn der linke Operand einer Verbund Zuweisung das Format E.P aufweist oder wenn E[Ei] E den Kompilier Zeittyp aufweist dynamic , wird die Zuweisung dynamisch gebunden (dynamische Bindung).If the left operand of a compound assignment is of the form E.P or E[Ei] where E has the compile-time type dynamic, then the assignment is dynamically bound (Dynamic binding). In diesem Fall ist der Kompilier Zeittyp des Zuweisungs Ausdrucks dynamic , und die unten beschriebene Auflösung erfolgt zur Laufzeit basierend auf dem Lauf Zeittyp von E .In this case the compile-time type of the assignment expression is dynamic, and the resolution described below will take place at run-time based on the run-time type of E.

Ein Vorgang des Formulars x op= y wird verarbeitet, indem die binäre Operator Überladungs Auflösung (binäre Operator Überladungs Auflösung) angewendet wird, als ob der Vorgang geschrieben wurde x op y .An operation of the form x op= y is processed by applying binary operator overload resolution (Binary operator overload resolution) as if the operation was written x op y. Dies ergibt folgende Szenarien:Then,

  • Wenn der Rückgabetyp des ausgewählten Operators implizit in den Typ von konvertiert x werden kann, wird der Vorgang als ausgewertet x = x op y , mit der Ausnahme, dass x nur einmal ausgewertet wird.If the return type of the selected operator is implicitly convertible to the type of x, the operation is evaluated as x = x op y, except that x is evaluated only once.
  • Andernfalls wird, wenn der ausgewählte Operator ein vordefinierter Operator ist, der Rückgabetyp des ausgewählten Operators explizit in den Typ von konvertiert x werden kann, und wenn y implizit in den Typ von konvertiert werden kann, x oder wenn der Operator ein Shift-Operator ist, wird der Vorgang als ausgewertet x = (T)(x op y) , wobei T der Typ von ist x , außer dass x nur einmal ausgewertet wird.Otherwise, if the selected operator is a predefined operator, if the return type of the selected operator is explicitly convertible to the type of x, and if y is implicitly convertible to the type of x or the operator is a shift operator, then the operation is evaluated as x = (T)(x op y), where T is the type of x, except that x is evaluated only once.
  • Andernfalls ist die Verbund Zuweisung ungültig, und es tritt ein Bindungs Zeitfehler auf.Otherwise, the compound assignment is invalid, and a binding-time error occurs.

Der Begriff "nur einmal ausgewertet" bedeutet, dass bei der Auswertung von x op y die Ergebnisse aller eingebenden Ausdrücke von x temporär gespeichert und dann wieder verwendet werden, wenn die Zuweisung zu erfolgt x .The term "evaluated only once" means that in the evaluation of x op y, the results of any constituent expressions of x are temporarily saved and then reused when performing the assignment to x. Beispielsweise werden in der A()[B()] += C() -Zuweisung, bei der A eine Methode zurückgibt int[] , und B und C sind Methoden zurückgegeben int , die-Methoden nur einmal in der Reihenfolge, A , aufgerufen B C .For example, in the assignment A()[B()] += C(), where A is a method returning int[], and B and C are methods returning int, the methods are invoked only once, in the order A, B, C.

Wenn der linke Operand einer Verbund Zuweisung ein Eigenschaften Zugriff oder ein Indexer-Zugriff ist, muss die Eigenschaft oder der Indexer sowohl einen get -Accessor als auch einen- set Accessor aufweisen.When the left operand of a compound assignment is a property access or indexer access, the property or indexer must have both a get accessor and a set accessor. Wenn dies nicht der Fall ist, tritt ein Bindungs Zeitfehler auf.If this is not the case, a binding-time error occurs.

Mit der zweiten obigen Regel x op= y können Sie x = (T)(x op y) in bestimmten Kontexten als ausgewertet werden.The second rule above permits x op= y to be evaluated as x = (T)(x op y) in certain contexts. Die Regel besteht darin, dass die vordefinierten Operatoren als Verbund Operatoren verwendet werden können, wenn der linke Operand vom Typ sbyte , byte , short , ushort oder ist char .The rule exists such that the predefined operators can be used as compound operators when the left operand is of type sbyte, byte, short, ushort, or char. Auch wenn beide Argumente von einem dieser Typen sind, führen die vordefinierten Operatoren zu einem Ergebnis vom Typ int , wie in Binäre numerischeErweiterungen beschrieben.Even when both arguments are of one of those types, the predefined operators produce a result of type int, as described in Binary numeric promotions. Daher wäre es ohne Umwandlung nicht möglich, das Ergebnis dem linken Operanden zuzuweisen.Thus, without a cast it would not be possible to assign the result to the left operand.

Die intuitive Auswirkung der Regel auf vordefinierte Operatoren ist nur x op= y zulässig, wenn sowohl x op y als auch zulässig x = y sind.The intuitive effect of the rule for predefined operators is simply that x op= y is permitted if both of x op y and x = y are permitted. Im BeispielIn the example

byte b = 0;
char ch = '\0';
int i = 0;

b += 1;             // Ok
b += 1000;          // Error, b = 1000 not permitted
b += i;             // Error, b = i not permitted
b += (byte)i;       // Ok

ch += 1;            // Error, ch = 1 not permitted
ch += (char)1;      // Ok

der intuitive Grund für jeden Fehler ist, dass eine entsprechende einfache Zuweisung ebenfalls ein Fehler wäre.the intuitive reason for each error is that a corresponding simple assignment would also have been an error.

Dies bedeutet auch, dass aufgesetzte Zuweisungs Vorgänge aufgesetzte Vorgänge unterstützen.This also means that compound assignment operations support lifted operations. Im BeispielIn the example

int? i = 0;
i += 1;             // Ok

der Operator "angehoben" +(int?,int?) wird verwendet.the lifted operator +(int?,int?) is used.

Ereignis ZuweisungEvent assignment

Wenn der linke Operand eines += or- -= Operators als Ereignis Zugriff klassifiziert ist, wird der Ausdruck wie folgt ausgewertet:If the left operand of a += or -= operator is classified as an event access, then the expression is evaluated as follows:

  • Der Instanzausdruck des Ereignis Zugriffs wird ausgewertet, falls vorhanden.The instance expression, if any, of the event access is evaluated.
  • Der rechte Operand des += Operators or -= wird ausgewertet und, falls erforderlich, durch eine implizite Konvertierung in den Typ des linken Operanden konvertiert (implizite Konvertierungen).The right operand of the += or -= operator is evaluated, and, if required, converted to the type of the left operand through an implicit conversion (Implicit conversions).
  • Ein Ereignis Accessor des Ereignisses wird mit einer Argumentliste aufgerufen, die den rechten Operanden nach der Auswertung und ggf. Konvertierung umfasst.An event accessor of the event is invoked, with argument list consisting of the right operand, after evaluation and, if necessary, conversion. Wenn der-Operator war += , add wird der-Accessor aufgerufen. wenn der-Operator war -= , wird der- remove Accessor aufgerufen.If the operator was +=, the add accessor is invoked; if the operator was -=, the remove accessor is invoked.

Ein Ereignis Zuweisungs Ausdruck ergibt keinen Wert.