ExpressionsExpressions

Une expression est une séquence d’opérateurs et d’opérandes.An expression is a sequence of operators and operands. Ce chapitre définit la syntaxe, l’ordre d’évaluation des opérandes et des opérateurs, ainsi que la signification des expressions.This chapter defines the syntax, order of evaluation of operands and operators, and meaning of expressions.

Classifications d’expressionsExpression classifications

Une expression est classée comme l'un des éléments suivants :An expression is classified as one of the following:

  • Valeur.A value. Chaque valeur possède un type associé.Every value has an associated type.
  • Variable.A variable. Chaque variable a un type associé, à savoir le type déclaré de la variable.Every variable has an associated type, namely the declared type of the variable.
  • Espace de noms.A namespace. Une expression avec cette classification ne peut apparaître qu’en tant que partie gauche d’un member_access (accès aux membres).An expression with this classification can only appear as the left hand side of a member_access (Member access). Dans tout autre contexte, une expression classée en tant qu’espace de noms provoque une erreur de compilation.In any other context, an expression classified as a namespace causes a compile-time error.
  • Type.A type. Une expression avec cette classification ne peut apparaître qu’en tant que partie gauche d’un member_access (accès aux membres), ou en tant qu’opérande pour l’opérateur as (opérateur as), l’opérateur is (opérateur is) ou le @no opérateur __t-6 (opérateur typeof).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). Dans tout autre contexte, une expression classifiée comme un type provoque une erreur au moment de la compilation.In any other context, an expression classified as a type causes a compile-time error.
  • Un groupe de méthodes, qui est un ensemble de méthodes surchargées résultant d’une recherche de membre (recherche de membre).A method group, which is a set of overloaded methods resulting from a member lookup (Member lookup). Un groupe de méthodes peut avoir une expression d’instance associée et une liste d’arguments de type associée.A method group may have an associated instance expression and an associated type argument list. Quand une méthode d’instance est appelée, le résultat de l’évaluation de l’expression d’instance devient l’instance représentée par this (cet accès).When an instance method is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access). Un groupe de méthodes est autorisé dans un invocation_expression (expressions d’appel), un delegate_creation_expression (expressions decréation de délégué) et comme côté gauche d’un opérateur is et peut être implicitement converti en un type délégué compatible (conversions de groupe de méthodes).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). Dans tout autre contexte, une expression classifiée comme un groupe de méthodes provoque une erreur au moment de la compilation.In any other context, an expression classified as a method group causes a compile-time error.
  • Littéral null.A null literal. Une expression avec cette classification peut être implicitement convertie en un type référence ou un type Nullable.An expression with this classification can be implicitly converted to a reference type or nullable type.
  • Fonction anonyme.An anonymous function. Une expression avec cette classification peut être convertie implicitement en un type délégué compatible ou un type d’arborescence d’expression.An expression with this classification can be implicitly converted to a compatible delegate type or expression tree type.
  • Accès à une propriété.A property access. Chaque accès à une propriété a un type associé, à savoir le type de la propriété.Every property access has an associated type, namely the type of the property. En outre, un accès à une propriété peut avoir une expression d’instance associée.Furthermore, a property access may have an associated instance expression. Lorsqu’un accesseur (le bloc get ou set) d’un accès à une propriété d’instance est appelé, le résultat de l’évaluation de l’expression d’instance devient l’instance représentée par this (cet accès).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).
  • Accès à un événement.An event access. Chaque accès à un événement a un type associé, à savoir le type de l’événement.Every event access has an associated type, namely the type of the event. En outre, un accès aux événements peut avoir une expression d’instance associée.Furthermore, an event access may have an associated instance expression. Un accès aux événements peut apparaître en tant qu’opérande gauche des opérateurs += et -= (assignation d’événement).An event access may appear as the left hand operand of the += and -= operators (Event assignment). Dans tout autre contexte, une expression classifiée comme un accès à un événement provoque une erreur de compilation.In any other context, an expression classified as an event access causes a compile-time error.
  • Un accès à un indexeur.An indexer access. Chaque accès à l’indexeur a un type associé, à savoir le type d’élément de l’indexeur.Every indexer access has an associated type, namely the element type of the indexer. En outre, un accès à un indexeur a une expression d’instance associée et une liste d’arguments associée.Furthermore, an indexer access has an associated instance expression and an associated argument list. Lorsqu’un accesseur (le bloc get ou set) d’un accès à un indexeur est appelé, le résultat de l’évaluation de l’expression d’instance devient l’instance représentée par this (cet accès), et le résultat de l’évaluation de la liste d’arguments devient le liste de paramètres de l’appel.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.
  • Rien.Nothing. Cela se produit lorsque l’expression est un appel d’une méthode avec un type de retour void.This occurs when the expression is an invocation of a method with a return type of void. Une expression classifiée comme Nothing n’est valide que dans le contexte d’un statement_expression (instructions d’expression).An expression classified as nothing is only valid in the context of a statement_expression (Expression statements).

Le résultat final d’une expression n’est jamais un espace de noms, un type, un groupe de méthodes ou un accès à un événement.The final result of an expression is never a namespace, type, method group, or event access. Au lieu de cela, comme indiqué ci-dessus, ces catégories d’expressions sont des constructions intermédiaires qui sont uniquement autorisées dans certains contextes.Rather, as noted above, these categories of expressions are intermediate constructs that are only permitted in certain contexts.

Un accès à une propriété ou un accès à un indexeur est toujours reclassifié comme valeur en effectuant un appel de l' accesseur Get ou de l' accesseur Set.A property access or indexer access is always reclassified as a value by performing an invocation of the get accessor or the set accessor. L’accesseur particulier est déterminé par le contexte de l’accès à la propriété ou à l’indexeur : Si l’accès est la cible d’une assignation, l' accesseur Set est appelé pour assigner une nouvelle valeur (assignation simple).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). Dans le cas contraire, l' accesseur Get est appelé pour obtenir la valeur actuelle (valeurs des expressions).Otherwise, the get accessor is invoked to obtain the current value (Values of expressions).

Valeurs des expressionsValues of expressions

La plupart des constructions qui impliquent une expression requièrent finalement que l’expression désigne une valeur.Most of the constructs that involve an expression ultimately require the expression to denote a value. Dans ce cas, si l’expression réelle désigne un espace de noms, un type, un groupe de méthodes ou rien, une erreur de compilation se produit.In such cases, if the actual expression denotes a namespace, a type, a method group, or nothing, a compile-time error occurs. Toutefois, si l’expression désigne un accès à une propriété, un indexeur ou une variable, la valeur de la propriété, de l’indexeur ou de la variable est implicitement remplacée :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:

  • La valeur d’une variable est simplement la valeur actuellement stockée dans l’emplacement de stockage identifié par la variable.The value of a variable is simply the value currently stored in the storage location identified by the variable. Une variable doit être considérée comme assignée de manière définitive (assignation définie) avant que sa valeur puisse être obtenue, sinon une erreur de compilation se produit.A variable must be considered definitely assigned (Definite assignment) before its value can be obtained, or otherwise a compile-time error occurs.
  • La valeur d’une expression d’accès à la propriété est obtenue en appelant l' accesseur Get de la propriété.The value of a property access expression is obtained by invoking the get accessor of the property. Si la propriété n’a pas d' accesseur Get, une erreur de compilation se produit.If the property has no get accessor, a compile-time error occurs. Sinon, un appel de membre de fonction (vérification au moment de la compilation de la résolution de surcharge dynamique) est effectué et le résultat de l’appel devient la valeur de l’expression d’accès à la propriété.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.
  • La valeur d’une expression d’accès à l’indexeur est obtenue en appelant l' accesseur Get de l’indexeur.The value of an indexer access expression is obtained by invoking the get accessor of the indexer. Si l’indexeur n’a pas d' accesseur Get, une erreur de compilation se produit.If the indexer has no get accessor, a compile-time error occurs. Sinon, un appel de membre de fonction (vérification au moment de la compilation de la résolution de surcharge dynamique) est effectué avec la liste d’arguments associée à l’expression d’accès de l’indexeur, et le résultat de l’appel devient la valeur de l’accès de l’indexeur formule.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.

Liaison statique et dynamiqueStatic and Dynamic Binding

Le processus de détermination de la signification d’une opération en fonction du type ou de la valeur des expressions constitutives (arguments, opérandes, récepteurs) est souvent appelé liaison.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. Par exemple, la signification d’un appel de méthode est déterminée en fonction du type du récepteur et des arguments.For instance the meaning of a method call is determined based on the type of the receiver and arguments. La signification d’un opérateur est déterminée en fonction du type de ses opérandes.The meaning of an operator is determined based on the type of its operands.

C# Le sens d’une opération est généralement déterminé au moment de la compilation, en fonction du type au moment de la compilation des expressions qui le composent.In C# the meaning of an operation is usually determined at compile-time, based on the compile-time type of its constituent expressions. De même, si une expression contient une erreur, l’erreur est détectée et signalée par le compilateur.Likewise, if an expression contains an error, the error is detected and reported by the compiler. Cette approche est connue sous le nom de liaison statique.This approach is known as static binding.

Toutefois, si une expression est une expression dynamique (par exemple, a le type dynamic), cela indique que toute liaison à laquelle elle participe doit être basée sur son type au moment de l’exécution (par exemple, le type réel de l’objet qu’elle désigne au moment de l’exécution) plutôt que le type dans lequel elle se trouve. au moment de la compilation.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. La liaison d’une telle opération est donc différée jusqu’au moment où l’opération doit être exécutée pendant l’exécution du programme.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. C’est ce que l’on appelle la liaison dynamique.This is referred to as dynamic binding.

Lorsqu’une opération est liée de manière dynamique, le compilateur n’effectue que peu ou pas de vérification.When an operation is dynamically bound, little or no checking is performed by the compiler. Au lieu de cela, si la liaison au moment de l’exécution échoue, les erreurs sont signalées en tant qu’exceptions au moment de l’exécution.Instead if the run-time binding fails, errors are reported as exceptions at run-time.

Les opérations suivantes dans C# sont soumises à la liaison :The following operations in C# are subject to binding:

  • Accès au membre : e.MMember access: e.M
  • Appel de méthode : e.M(e1, ..., eN)Method invocation: e.M(e1, ..., eN)
  • Appel de délégué : e(e1, ..., eN)Delegate invocation:e(e1, ..., eN)
  • Accès à l’élément : e[e1, ..., eN]Element access: e[e1, ..., eN]
  • Création d’objet : new C(e1, ..., eN)Object creation: new C(e1, ..., eN)
  • Opérateurs unaires surchargés : +, -, !, ~, ++, --, true, falseOverloaded unary operators: +, -, !, ~, ++, --, true, false
  • Opérateurs binaires surchargés : +, -, *, /, %, &, &&, |, ||, ??, 0, 1, 2, 3, 4, 5, 6, 7, 8Overloaded binary operators: +, -, *, /, %, &, &&, |, ||, ??, ^, <<, >>, ==,!=, >, <, >=, <=
  • Opérateurs d’assignation : =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, 0Assignment operators: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
  • Conversions implicites et explicitesImplicit and explicit conversions

Quand aucune expression dynamique n’est impliquée, C# la valeur par défaut est la liaison statique, ce qui signifie que les types de compilation des expressions constitutives sont utilisés dans le processus de sélection.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. Toutefois, lorsque l’une des expressions constitutives des opérations listées ci-dessus est une expression dynamique, l’opération est liée dynamiquement.However, when one of the constituent expressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound.

Liaison-heureBinding-time

La liaison statique a lieu au moment de la compilation, tandis que la liaison dynamique a lieu au moment de l’exécution.Static binding takes place at compile-time, whereas dynamic binding takes place at run-time. Dans les sections suivantes, le terme « Binding-Time » fait référence à la compilation ou au moment de l’exécution, selon le moment où la liaison a lieu.In the following sections, the term binding-time refers to either compile-time or run-time, depending on when the binding takes place.

L’exemple suivant illustre les notions de liaison statique et dynamique et de l’heure de liaison :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)

Les deux premiers appels sont liés statiquement : la surcharge de Console.WriteLine est choisie en fonction du type au moment de la compilation de leur argument.The first two calls are statically bound: the overload of Console.WriteLine is picked based on the compile-time type of their argument. Ainsi, la durée de la liaison est au moment de la compilation.Thus, the binding-time is compile-time.

Le troisième appel est lié dynamiquement : la surcharge de Console.WriteLine est choisie en fonction du type au moment de l’exécution de son argument.The third call is dynamically bound: the overload of Console.WriteLine is picked based on the run-time type of its argument. Cela se produit parce que l’argument est une expression dynamique--son type au moment de la compilation est dynamic.This happens because the argument is a dynamic expression -- its compile-time type is dynamic. Ainsi, le temps de liaison pour le troisième appel est au moment de l’exécution.Thus, the binding-time for the third call is run-time.

Liaison dynamiqueDynamic binding

L’objectif de la liaison dynamique est de C# permettre aux programmes d’interagir avec des objets dynamiques, c’est-à-dire des objets qui ne respectent pas les règles C# normales du système de type.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. Les objets dynamiques peuvent être des objets provenant d’autres langages de programmation avec des systèmes de types différents, ou des objets qui sont configurés par programme pour implémenter leur propre sémantique de liaison pour différentes opérations.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.

Le mécanisme par lequel un objet dynamique implémente sa propre sémantique est défini par l’implémentation.The mechanism by which a dynamic object implements its own semantics is implementation defined. Une interface donnée, à nouveau définie, est implémentée par les objets dynamiques pour signaler au moment C# de l’exécution qu’ils ont une sémantique spéciale.A given interface -- again implementation defined -- is implemented by dynamic objects to signal to the C# run-time that they have special semantics. Par conséquent, chaque fois que des opérations sur un objet dynamique sont liées de manière dynamique, leur propre sémantique de liaison C# , plutôt que celles de telles qu’elles sont spécifiées dans ce document, prennent le contrôle.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.

Bien que l’objectif de la liaison dynamique soit d’autoriser l’interopérabilité avec C# les objets dynamiques, autorise la liaison dynamique sur tous les objets, qu’ils soient dynamiques ou non.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. Cela permet une intégration plus fluide des objets dynamiques, car les résultats des opérations sur ceux-ci peuvent ne pas être eux-mêmes des objets dynamiques, mais ils sont toujours d’un type inconnu pour le programmeur au moment de la compilation.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. En outre, la liaison dynamique permet d’éliminer le code basé sur la réflexion, susceptible d’engendrer des erreurs, même quand aucun objet impliqué n’est un objet dynamique.Also dynamic binding can help eliminate error-prone reflection-based code even when no objects involved are dynamic objects.

Les sections suivantes décrivent pour chaque construction dans le langage exactement quand la liaison dynamique est appliquée, la vérification du temps de compilation, le cas échéant, et le résultat de la classification des expressions et des résultats au moment de la compilation.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.

Types d’expressions constitutivesTypes of constituent expressions

Lorsqu’une opération est liée de manière statique, le type d’une expression de composant (par exemple, un récepteur, un argument, un index ou un opérande) est toujours considéré comme le type au moment de la compilation de cette expression.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.

Lorsqu’une opération est liée de manière dynamique, le type d’une expression constitutive est déterminé de différentes manières selon le type de compilation de l’expression constitutive :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:

  • Une expression constitutive du type au moment de la compilation dynamic est considérée comme ayant le type de la valeur réelle évaluée par l’expression au moment de l’exécutionA constituent expression of compile-time type dynamic is considered to have the type of the actual value that the expression evaluates to at runtime
  • Une expression de composant dont le type au moment de la compilation est un paramètre de type est considérée comme ayant le type auquel le paramètre de type est lié au moment de l’exécutionA 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
  • Dans le cas contraire, l’expression constitutive est considérée comme ayant le type au moment de la compilation.Otherwise the constituent expression is considered to have its compile-time type.

OpérateursOperators

Les expressions sont construites à partir d' opérandes et d' opérateurs.Expressions are constructed from operands and operators. Les opérateurs d’une expression indiquent les opérations à appliquer aux opérandes.The operators of an expression indicate which operations to apply to the operands. Parmi les exemples d’opérateurs figurent +, -, *, / et new.Examples of operators include +, -, *, /, and new. Les littéraux, les champs, les variables locales et les expressions sont des exemples d’opérandes.Examples of operands include literals, fields, local variables, and expressions.

Il existe trois types d’opérateurs :There are three kinds of operators:

  • Les opérateurs unaires.Unary operators. Les opérateurs unaires acceptent un opérande et utilisent soit la notation de préfixe (par exemple --x), soit la notation suffixée (comme x++).The unary operators take one operand and use either prefix notation (such as --x) or postfix notation (such as x++).
  • Opérateurs binaires.Binary operators. Les opérateurs binaires acceptent deux opérandes et utilisent tous la notation infix (par exemple, x + y).The binary operators take two operands and all use infix notation (such as x + y).
  • Opérateur ternaire.Ternary operator. Un seul opérateur ternaire, ?:, existe ; Il prend trois opérandes et utilise la notation infixe (c ? x : y).Only one ternary operator, ?:, exists; it takes three operands and uses infix notation (c ? x : y).

L’ordre d’évaluation des opérateurs dans une expression est déterminé par la priorité et l' associativité des opérateurs (priorité et associativitédes opérateurs).The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators (Operator precedence and associativity).

Les opérandes d’une expression sont évalués de gauche à droite.Operands in an expression are evaluated from left to right. Par exemple, dans F(i) + G(i++) * H(i), la méthode F est appelée à l’aide de l’ancienne valeur de i, puis la méthode G est appelée avec l’ancienne valeur de i et, enfin, la méthode H est appelée avec la nouvelle valeur de 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. Cela est indépendant de et non lié à la priorité des opérateurs.This is separate from and unrelated to operator precedence.

Certains opérateurs peuvent être surchargés.Certain operators can be overloaded. La surcharge d’opérateur permet de spécifier des implémentations d’opérateur définies par l’utilisateur pour les opérations où l’un des opérandes ou les deux sont d’un type de classe ou de struct défini par l’utilisateur (surcharge d’opérateur).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).

Priorité des opérateurs et associativitéOperator precedence and associativity

Quand une expression contient plusieurs opérateurs, la priorité des opérateurs contrôle l'ordre dans lequel les opérateurs individuels sont évalués.When an expression contains multiple operators, the precedence of the operators controls the order in which the individual operators are evaluated. Par exemple, l’expression x + y * z est évaluée comme x + (y * z), car l’opérateur * a une priorité plus élevée que l’opérateur binaire +.For example, the expression x + y * z is evaluated as x + (y * z) because the * operator has higher precedence than the binary + operator. La priorité d’un opérateur est établie par la définition de sa production grammaticale associée.The precedence of an operator is established by the definition of its associated grammar production. Par exemple, un additive_expression se compose d’une séquence de multiplicative_expressions séparés par des opérateurs + ou -, donnant ainsi aux opérateurs + et - une priorité plus faible que les *, / et @no__ opérateurs t-8.For example, an additive_expression consists of a sequence of multiplicative_expressions separated by + or - operators, thus giving the + and - operators lower precedence than the *, /, and % operators.

Le tableau suivant récapitule tous les opérateurs par ordre de priorité, du plus élevé au plus bas :The following table summarizes all operators in order of precedence from highest to lowest:

SectionSection CatégorieCategory OpérateursOperators
Expressions primairesPrimary expressions PrincipalePrimary 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
Opérateurs unairesUnary operators UnaireUnary + - ! ~ ++x --x (T)x+ - ! ~ ++x --x (T)x
Opérateurs arithmétiquesArithmetic operators MultiplicationMultiplicative * / %* / %
Opérateurs arithmétiquesArithmetic operators AdditionAdditive + -+ -
Opérateurs de décalageShift operators ShiftShift << >><< >>
Opérateurs relationnels et de test de typeRelational and type-testing operators Relations et test de typeRelational and type testing < > <= >= is as< > <= >= is as
Opérateurs relationnels et de test de typeRelational and type-testing operators ÉgalitéEquality == !=== !=
Opérateurs logiquesLogical operators AND logiqueLogical AND &
Opérateurs logiquesLogical operators XOR logiqueLogical XOR ^
Opérateurs logiquesLogical operators OR logiqueLogical OR |
Opérateurs logiques conditionnelsConditional logical operators AND conditionnelConditional AND &&
Opérateurs logiques conditionnelsConditional logical operators OR conditionnelConditional OR ||
Opérateur de fusion de NullThe null coalescing operator Fusion de NullNull coalescing ??
Opérateur conditionnelConditional operator ConditionnelConditional ?:
Opérateurs d’assignation, expressions de fonction anonymesAssignment operators, Anonymous function expressions Assignation et expression lambdaAssignment and lambda expression = *= /= %= += -= <<= >>= &= ^= |= =>= *= /= %= += -= <<= >>= &= ^= |= =>

Lorsqu’un opérande se produit entre deux opérateurs ayant la même priorité, l’associativité des opérateurs contrôle l’ordre dans lequel les opérations sont effectuées :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:

  • À l’exception des opérateurs d’assignation et de l’opérateur de fusion Null, tous les opérateurs binaires sont associatifs à gauche, ce qui signifie que les opérations sont effectuées de gauche à droite.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. Par exemple, x + y + z est évalué comme étant (x + y) + z.For example, x + y + z is evaluated as (x + y) + z.
  • Les opérateurs d’assignation, l’opérateur de fusion Null et l’opérateur conditionnel (?:) sont associatifs à droite, ce qui signifie que les opérations sont exécutées de droite à gauche.The assignment operators, the null coalescing operator and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. Par exemple, x = y = z est évalué comme étant x = (y = z).For example, x = y = z is evaluated as x = (y = z).

La priorité et l’associativité peuvent être contrôlées à l’aide de parenthèses.Precedence and associativity can be controlled using parentheses. Par exemple, x + y * z multiplie d’abord y par z, puis ajoute le résultat à x, mais (x + y) * z ajoute d’abord x et y, puis multiplie le résultat par z.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.

Surcharge d’opérateurOperator overloading

Tous les opérateurs unaires et binaires ont des implémentations prédéfinies qui sont automatiquement disponibles dans toute expression.All unary and binary operators have predefined implementations that are automatically available in any expression. Outre les implémentations prédéfinies, les implémentations définies par l’utilisateur peuvent être introduites en incluant des déclarations operator dans des classes et des structs (opérateurs).In addition to the predefined implementations, user-defined implementations can be introduced by including operator declarations in classes and structs (Operators). Les implémentations d’opérateur définies par l’utilisateur ont toujours priorité sur les implémentations d’opérateur prédéfinies : Les implémentations d’opérateur prédéfinies sont prises en compte uniquement lorsqu’il n’existe pas d’implémentations d’opérateur définies par l’utilisateur applicables, comme décrit dans résolution de surcharge d’opérateur unaire et résolution de surcharge d’opérateur binaire.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.

Les opérateurs unaires surchargeables sont :The overloadable unary operators are:

+   -   !   ~   ++   --   true   false

Même si true et false ne sont pas utilisés explicitement dans les expressions (et ne sont donc pas inclus dans la table de précédence dans la priorité et l’associativité des opérateurs), ils sont considérés comme des opérateurs, car ils sont appelés dans plusieurs expressions contextes : expressions booléennes (expressions booléennes) et expressions impliquant l'opérateurconditionnel (conditionnel) et opérateurs logiques conditionnels (opérateurs logiques conditionnels).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).

Les opérateurs binaires surchargeables sont les suivants :The overloadable binary operators are:

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

Seuls les opérateurs listés ci-dessus peuvent être surchargés.Only the operators listed above can be overloaded. En particulier, il n’est pas possible de surcharger l’accès aux membres, l’appel de méthode ou les =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, 0, 1 et 2.In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, as, and is operators.

Quand un opérateur binaire est surchargé, l’opérateur d’assignation correspondant, le cas échéant, est aussi implicitement surchargé.When a binary operator is overloaded, the corresponding assignment operator, if any, is also implicitly overloaded. Par exemple, une surcharge de l’opérateur * est également une surcharge de l’opérateur *=.For example, an overload of operator * is also an overload of operator *=. Cela est décrit plus en détail dans assignation composée.This is described further in Compound assignment. Notez que l’opérateur d’assignation lui-même (=) ne peut pas être surchargé.Note that the assignment operator itself (=) cannot be overloaded. Une assignation effectue toujours une simple copie bit-wise d’une valeur dans une variable.An assignment always performs a simple bit-wise copy of a value into a variable.

Les opérations de cast, telles que (T)x, sont surchargées en fournissant des conversions définies par l’utilisateur (conversions définies par l’utilisateur).Cast operations, such as (T)x, are overloaded by providing user-defined conversions (User-defined conversions).

L’accès aux éléments, tel que a[x], n’est pas considéré comme un opérateur surchargeable.Element access, such as a[x], is not considered an overloadable operator. À la place, l’indexation définie par l’utilisateur est prise en charge par le biais d’indexeurs (indexeurs).Instead, user-defined indexing is supported through indexers (Indexers).

Dans les expressions, les opérateurs sont référencés à l’aide de la notation opérateur, et dans les déclarations, les opérateurs sont référencés à l’aide de la notation fonctionnelle.In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. Le tableau suivant montre la relation entre les notations opérateur et opérateur pour les opérateurs unaires et binaires.The following table shows the relationship between operator and functional notations for unary and binary operators. Dans la première entrée, op dénote n’importe quel opérateur de préfixe unaire surchargeable.In the first entry, op denotes any overloadable unary prefix operator. Dans la deuxième entrée, op dénote les opérateurs suffixe unaire ++ et --.In the second entry, op denotes the unary postfix ++ and -- operators. Dans la troisième entrée, op dénote tout opérateur binaire surchargeable.In the third entry, op denotes any overloadable binary operator.

Notation d’opérateurOperator notation Notation fonctionnelleFunctional notation
op x operator op(x)
x op operator op(x)
x op y operator op(x,y)

Les déclarations d’opérateur définies par l’utilisateur requièrent toujours qu’au moins un des paramètres soit du type de classe ou de struct qui contient la déclaration d’opérateur.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. Par conséquent, il n’est pas possible pour un opérateur défini par l’utilisateur d’avoir la même signature qu’un opérateur prédéfini.Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.

Les déclarations d’opérateur définies par l’utilisateur ne peuvent pas modifier la syntaxe, la priorité ou l’associativité d’un opérateur.User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. Par exemple, l’opérateur / est toujours un opérateur binaire, possède toujours le niveau de précédence spécifié dans priorité et associativité des opérateurs, et est toujours associatif à gauche.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.

Bien qu’il soit possible pour un opérateur défini par l’utilisateur d’effectuer n’importe quel calcul, les implémentations qui produisent des résultats autres que ceux qui sont intuitivement attendus sont fortement déconseillées.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. Par exemple, une implémentation de operator == doit comparer les deux opérandes pour l’égalité et retourner un résultat bool approprié.For example, an implementation of operator == should compare the two operands for equality and return an appropriate bool result.

Les descriptions des opérateurs individuels dans les expressions primaires par le biais d' opérateurs logiques conditionnels spécifient les implémentations prédéfinies des opérateurs et toutes les règles supplémentaires qui s’appliquent à chaque opérateur.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. Les descriptions utilisent les termes résolution de surcharge d’opérateur unaire, résolution de surcharge d’opérateur binaireet promotion numérique, dont les définitions se trouvent dans les sections suivantes.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.

Résolution de surcharge d’opérateur unaireUnary operator overload resolution

Une opération de la forme op x ou x op, où op est un opérateur unaire surchargeable, et x est une expression de type X, est traitée comme suit :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:

  • L’ensemble d’opérateurs candidats définis par l’utilisateur fourni par X pour l’opération operator op(x) est déterminé à l’aide des règles des opérateurs candidats définispar l’utilisateur.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.
  • Si le jeu d’opérateurs candidats définis par l’utilisateur n’est pas vide, il devient alors l’ensemble des opérateurs candidats pour l’opération.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Sinon, les implémentations unaires prédéfinies de operator op, y compris leurs formes levées, deviennent l’ensemble des opérateurs candidats pour l’opération.Otherwise, the predefined unary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Les implémentations prédéfinies d’un opérateur donné sont spécifiées dans la description de l’opérateur (expressions primaires et opérateurs unaires).The predefined implementations of a given operator are specified in the description of the operator (Primary expressions and Unary operators).
  • Les règles de résolution de surcharge de la résolution de surcharge sont appliquées au jeu d’opérateurs candidats pour sélectionner le meilleur opérateur par rapport à la liste d’arguments (x), et cet opérateur devient le résultat du processus de résolution de surcharge.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. Si la résolution de surcharge ne peut pas sélectionner un seul opérateur Best, une erreur de liaison est générée.If overload resolution fails to select a single best operator, a binding-time error occurs.

Résolution de surcharge d’opérateur binaireBinary operator overload resolution

Opération de la forme x op y, où op est un opérateur binaire surchargeable, x est une expression de type X, et y est une expression de type Y, est traité comme suit :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:

  • L’ensemble d’opérateurs candidats définis par l’utilisateur fourni par X et Y pour l’opération operator op(x,y) est déterminé.The set of candidate user-defined operators provided by X and Y for the operation operator op(x,y) is determined. L’ensemble se compose de l’Union des opérateurs candidats fournis par X et des opérateurs candidats fournis par Y, chacun étant déterminé à l’aide des règles des opérateurs candidats définispar l’utilisateur.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. Si X et Y sont du même type, ou si X et Y sont dérivés d’un type de base commun, les opérateurs candidats partagés ne se produisent que dans l’ensemble combiné une fois.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.
  • Si le jeu d’opérateurs candidats définis par l’utilisateur n’est pas vide, il devient alors l’ensemble des opérateurs candidats pour l’opération.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Dans le cas contraire, les implémentations binaires prédéfinies operator op, y compris leurs formulaires levés, deviennent l’ensemble des opérateurs candidats pour l’opération.Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Les implémentations prédéfinies d’un opérateur donné sont spécifiées dans la description de l’opérateur (opérateurs arithmétiques à l’aide d' opérateurs logiques conditionnels).The predefined implementations of a given operator are specified in the description of the operator (Arithmetic operators through Conditional logical operators). Pour les opérateurs enum et Delegate prédéfinis, les seuls opérateurs pris en compte sont ceux définis par un type enum ou Delegate qui est le type de temps de liaison de l’un des opérandes.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.
  • Les règles de résolution de surcharge de la résolution de surcharge sont appliquées au jeu d’opérateurs candidats pour sélectionner le meilleur opérateur par rapport à la liste d’arguments (x,y), et cet opérateur devient le résultat du processus de résolution de surcharge.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. Si la résolution de surcharge ne peut pas sélectionner un seul opérateur Best, une erreur de liaison est générée.If overload resolution fails to select a single best operator, a binding-time error occurs.

Opérateurs candidats définis par l’utilisateurCandidate user-defined operators

Étant donné un type T et une opération operator op(A), où op est un opérateur surchargeable et A est une liste d’arguments, l’ensemble des opérateurs candidats définis par l’utilisateur fournis par T pour operator op(A) est déterminé comme suit :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:

  • Déterminez le type T0.Determine the type T0. Si T est un type Nullable, T0 est son type sous-jacent, sinon T0 est égal à T.If T is a nullable type, T0 is its underlying type, otherwise T0 is equal to T.
  • Pour toutes les déclarations operator op dans T0 et toutes les formes levées de tels opérateurs, si au moins un opérateur est applicable (membre de fonction applicable) en ce qui concerne la liste d’arguments A, alors l’ensemble des opérateurs candidats est constitué de tout. opérateurs applicables dans 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.
  • Sinon, si T0 est object, l’ensemble des opérateurs candidats est vide.Otherwise, if T0 is object, the set of candidate operators is empty.
  • Sinon, le jeu d’opérateurs candidats fourni par T0 est l’ensemble des opérateurs candidats fournis par la classe de base directe de T0, ou la classe de base effective de T0 si T0 est un paramètre de type.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.

Promotions numériquesNumeric promotions

La promotion numérique consiste à effectuer automatiquement certaines conversions implicites des opérandes des opérateurs numériques unaires et binaires prédéfinis.Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. La promotion numérique n’est pas un mécanisme distinct, mais plutôt un effet de l’application de la résolution de surcharge aux opérateurs prédéfinis.Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. La promotion numérique n’affecte pas spécifiquement l’évaluation des opérateurs définis par l’utilisateur, bien que les opérateurs définis par l’utilisateur puissent être implémentés pour présenter des effets similaires.Numeric promotion specifically does not affect evaluation of user-defined operators, although user-defined operators can be implemented to exhibit similar effects.

À titre d’exemple de promotion numérique, prenez en compte les implémentations prédéfinies de l’opérateur binaire * :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);

Lorsque des règles de résolution de surcharge (résolution de surcharge) sont appliquées à cet ensemble d’opérateurs, l’effet est de sélectionner le premier des opérateurs pour lesquels des conversions implicites existent à partir des types d’opérandes.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. Par exemple, pour l’opération b * s, où b est un byte et s est une short, la résolution de surcharge sélectionne operator *(int,int) comme meilleur opérateur.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. Par conséquent, l’effet est que b et s sont convertis en int, et que le type du résultat est int.Thus, the effect is that b and s are converted to int, and the type of the result is int. De même, pour l’opération i * d, où i est un int et d est une double, la résolution de surcharge sélectionne operator *(double,double) comme meilleur opérateur.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.

Promotions numériques unairesUnary numeric promotions

La promotion numérique unaire se produit pour les opérandes des opérateurs unaires prédéfinis +, - et ~.Unary numeric promotion occurs for the operands of the predefined +, -, and ~ unary operators. La promotion numérique unaire consiste simplement à convertir les opérandes de type sbyte, byte, short, ushort ou char en type int.Unary numeric promotion simply consists of converting operands of type sbyte, byte, short, ushort, or char to type int. En outre, pour l’opérateur unaire -, la promotion numérique unaire convertit les opérandes de type uint en type long.Additionally, for the unary - operator, unary numeric promotion converts operands of type uint to type long.

Promotions numériques binairesBinary numeric promotions

La promotion numérique binaire se produit pour les opérandes des opérateurs prédéfinis +, -, *, /, %, &, |, ^, ==, !=, 0, 1, 2 et 3.Binary numeric promotion occurs for the operands of the predefined +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. La promotion numérique binaire convertit implicitement les deux opérandes en un type commun qui, dans le cas des opérateurs non relationnels, devient également le type de résultat de l’opération.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. La promotion numérique binaire consiste à appliquer les règles suivantes, dans l’ordre où elles apparaissent ici :Binary numeric promotion consists of applying the following rules, in the order they appear here:

  • Si l’un des opérandes est de type decimal, l’autre opérande est converti en type decimal, ou une erreur de liaison se produit si l’autre opérande est de type float ou 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.
  • Sinon, si l’un des opérandes est de type double, l’autre opérande est converti en type double.Otherwise, if either operand is of type double, the other operand is converted to type double.
  • Sinon, si l’un des opérandes est de type float, l’autre opérande est converti en type float.Otherwise, if either operand is of type float, the other operand is converted to type float.
  • Sinon, si l’un des opérandes est de type ulong, l’autre opérande est converti en type ulong, ou une erreur de liaison se produit si l’autre opérande est de type sbyte, short, int ou 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.
  • Sinon, si l’un des opérandes est de type long, l’autre opérande est converti en type long.Otherwise, if either operand is of type long, the other operand is converted to type long.
  • Sinon, si l’un des opérandes est de type uint et que l’autre opérande est de type sbyte, short ou int, les deux opérandes sont convertis en type 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.
  • Sinon, si l’un des opérandes est de type uint, l’autre opérande est converti en type uint.Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • Sinon, les deux opérandes sont convertis en type int.Otherwise, both operands are converted to type int.

Notez que la première règle interdit toutes les opérations qui combinent le type decimal avec les types double et float.Note that the first rule disallows any operations that mix the decimal type with the double and float types. La règle suit du fait qu’il n’y a pas de conversion implicite entre le type decimal et les types double et float.The rule follows from the fact that there are no implicit conversions between the decimal type and the double and float types.

Notez également qu’il n’est pas possible qu’un opérande soit de type ulong quand l’autre opérande est d’un type intégral signé.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. La raison est qu’il n’existe aucun type intégral qui peut représenter la plage complète de ulong, ainsi que les types intégraux signés.The reason is that no integral type exists that can represent the full range of ulong as well as the signed integral types.

Dans les deux cas ci-dessus, une expression de cast peut être utilisée pour convertir explicitement un opérande en un type compatible avec l’autre opérande.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.

Dans l’exempleIn the example

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

une erreur de liaison s’est produite, car un decimal ne peut pas être multiplié par un double.a binding-time error occurs because a decimal cannot be multiplied by a double. L’erreur est résolue par la conversion explicite du deuxième opérande en decimal, comme suit :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);
}

Opérateurs levésLifted operators

Les opérateurs levés permettent aux opérateurs prédéfinis et définis par l’utilisateur qui fonctionnent sur des types valeur non Nullable d’être également utilisés avec les formulaires Nullable de ces types.Lifted operators permit predefined and user-defined operators that operate on non-nullable value types to also be used with nullable forms of those types. Les opérateurs levés sont construits à partir d’opérateurs prédéfinis et définis par l’utilisateur qui répondent à certaines exigences, comme décrit dans les rubriques suivantes :Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:

  • Pour les opérateurs unairesFor the unary operators

    +  ++  -  --  !  ~
    

    une forme levée d’un opérateur existe si l’opérande et les types de résultats sont des types valeur non Nullable.a lifted form of an operator exists if the operand and result types are both non-nullable value types. Le formulaire levé est construit en ajoutant un modificateur ? unique aux types d’opérandes et de résultats.The lifted form is constructed by adding a single ? modifier to the operand and result types. L’opérateur levé produit une valeur null si l’opérande a la valeur null.The lifted operator produces a null value if the operand is null. Dans le cas contraire, l’opérateur Levé désencapsule l’opérande, applique l’opérateur sous-jacent et encapsule le résultat.Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.

  • Pour les opérateurs binairesFor the binary operators

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

    une forme levée d’un opérateur existe si l’opérande et les types de résultats sont tous des types valeur non Nullable.a lifted form of an operator exists if the operand and result types are all non-nullable value types. Le formulaire levé est construit en ajoutant un seul modificateur ? à chaque opérande et chaque type de résultat.The lifted form is constructed by adding a single ? modifier to each operand and result type. L’opérateur levé produit une valeur null si un ou les deux opérandes ont la valeur null (une exception étant les opérateurs & et | du type bool?, comme décrit dans opérateurs logiques booléens).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). Dans le cas contraire, l’opérateur Levé désencapsule les opérandes, applique l’opérateur sous-jacent et encapsule le résultat.Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.

  • Pour les opérateurs d’égalitéFor the equality operators

    ==  !=
    

    une forme levée d’un opérateur existe si les types d’opérandes sont des types valeur non Nullable et si le type de résultat est 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. Le formulaire levé est construit en ajoutant un seul modificateur ? à chaque type d’opérande.The lifted form is constructed by adding a single ? modifier to each operand type. L’opérateur levé considère deux valeurs NULL comme étant égales et une valeur NULL n’est pas égale à une valeur non null.The lifted operator considers two null values equal, and a null value unequal to any non-null value. Si les deux opérandes n’ont pas la valeur null, l’opérateur Levé désencapsule les opérandes et applique l’opérateur sous-jacent pour produire le résultat bool.If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

  • Pour les opérateurs relationnelsFor the relational operators

    <  >  <=  >=
    

    une forme levée d’un opérateur existe si les types d’opérandes sont des types valeur non Nullable et si le type de résultat est 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. Le formulaire levé est construit en ajoutant un seul modificateur ? à chaque type d’opérande.The lifted form is constructed by adding a single ? modifier to each operand type. L’opérateur levé produit la valeur false si un ou les deux opérandes ont la valeur null.The lifted operator produces the value false if one or both operands are null. Dans le cas contraire, l’opérateur Levé désencapsule les opérandes et applique l’opérateur sous-jacent pour produire le résultat bool.Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

Recherche de membresMember lookup

Une recherche de membre est le processus par lequel la signification d’un nom dans le contexte d’un type est déterminée.A member lookup is the process whereby the meaning of a name in the context of a type is determined. Une recherche de membre peut se produire dans le cadre de l’évaluation d’un simple_name (noms simples) ou d’un member_access (accès aux membres) dans une expression.A member lookup can occur as part of evaluating a simple_name (Simple names) or a member_access (Member access) in an expression. Si simple_name ou member_access se produit comme primary_expression d’un invocation_expression (appels de méthode), le membre est dit appelé.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.

Si un membre est une méthode ou un événement, ou s’il s’agit d’une constante, d’un champ ou d’une propriété d’un type délégué (délégués) ou du type dynamic (type dynamique), le membre est dit être invocable.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.

La recherche de membres prend en compte non seulement le nom d’un membre, mais également le nombre de paramètres de type que le membre possède et si le membre est accessible.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. Dans le cadre de la recherche de membres, les méthodes génériques et les types génériques imbriqués ont le nombre de paramètres de type indiqué dans leurs déclarations respectives et tous les autres membres ont des paramètres de type zéro.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.

Une recherche de membre portant le nom @ no__t-0 avec les paramètres K @ no__t-2Type dans un type @ no__t-3 est traitée comme suit :A member lookup of a name N with K type parameters in a type T is processed as follows:

  • Tout d’abord, un ensemble de membres accessibles nommés @ no__t-0 est déterminé :First, a set of accessible members named N is determined:
    • Si T est un paramètre de type, le jeu est l’Union des ensembles de membres accessibles nommés @ no__t-1 dans chacun des types spécifiés en tant que contrainte principale ou contrainte secondaire (contraintes de paramètre de type) pour @ no__t-3, avec l’ensemble de les membres accessibles nommés @ no__t-4 dans 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.
    • Dans le cas contraire, l’ensemble se compose de tous les membres accessibles (accès aux membres) nommés @ no__t-1 dans @ no__t-2, y compris les membres hérités et les membres accessibles nommés @ no__t-3 dans 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. Si T est un type construit, l’ensemble de membres est obtenu en remplaçant les arguments de type comme décrit dans membres des types construits.If T is a constructed type, the set of members is obtained by substituting type arguments as described in Members of constructed types. Les membres qui incluent un modificateur override sont exclus de l’ensemble.Members that include an override modifier are excluded from the set.
  • Ensuite, si K est égal à zéro, tous les types imbriqués dont les déclarations incluent des paramètres de type sont supprimés.Next, if K is zero, all nested types whose declarations include type parameters are removed. Si K n’est pas égal à zéro, tous les membres avec un nombre différent de paramètres de type sont supprimés.If K is not zero, all members with a different number of type parameters are removed. Notez que lorsque K est égal à zéro, les méthodes ayant des paramètres de type ne sont pas supprimées, car le processus d’inférence de type (inférence de type) peut être en mesure de déduire les arguments de type.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.
  • Ensuite, si le membre est appelé, tous les membres qui ne sont pasinvocables sont supprimés du jeu.Next, if the member is invoked, all non-invocable members are removed from the set.
  • Ensuite, les membres qui sont masqués par d’autres membres sont supprimés du jeu.Next, members that are hidden by other members are removed from the set. Pour chaque membre S.M dans l’ensemble, où S est le type dans lequel le membre @ no__t-2 est déclaré, les règles suivantes sont appliquées :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:
    • Si M est une constante, un champ, une propriété, un événement ou un membre de l’énumération, tous les membres déclarés dans un type de base de S sont supprimés du jeu.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.
    • Si M est une déclaration de type, tous les types non déclarés dans un type de base de S sont supprimés du jeu, et toutes les déclarations de type avec le même nombre de paramètres de type que M déclarés dans un type de base de S sont supprimées de l’ensemble.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.
    • Si M est une méthode, tous les membres qui ne sont pas des méthodes déclarés dans un type de base de S sont supprimés du jeu.If M is a method, then all non-method members declared in a base type of S are removed from the set.
  • Ensuite, les membres d’interface qui sont masqués par les membres de classe sont supprimés du jeu.Next, interface members that are hidden by class members are removed from the set. Cette étape n’a d’effet que si T est un paramètre de type et que T a une classe de base effective autre que object et un ensemble d’interfaces effectif non vide (contraintes de paramètre de type).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). Pour chaque membre S.M dans l’ensemble, où S est le type dans lequel le membre M est déclaré, les règles suivantes sont appliquées si S est une déclaration de classe autre que 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:
    • Si M est un constante, un champ, une propriété, un événement, un membre de l’énumération ou une déclaration de type, tous les membres déclarés dans une déclaration d’interface sont supprimés du jeu.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.
    • Si M est une méthode, tous les membres qui ne sont pas des méthodes déclarés dans une déclaration d’interface sont supprimés du jeu, et toutes les méthodes ayant la même signature que M déclarées dans une déclaration d’interface sont supprimées de l’ensemble.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.
  • Enfin, si vous avez supprimé des membres masqués, le résultat de la recherche est déterminé :Finally, having removed hidden members, the result of the lookup is determined:
    • Si l’ensemble se compose d’un seul membre qui n’est pas une méthode, ce membre est le résultat de la recherche.If the set consists of a single member that is not a method, then this member is the result of the lookup.
    • Sinon, si l’ensemble contient uniquement des méthodes, ce groupe de méthodes est le résultat de la recherche.Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
    • Dans le cas contraire, la recherche est ambiguë et une erreur de liaison s’est produite.Otherwise, the lookup is ambiguous, and a binding-time error occurs.

Pour les recherches de membres dans les types autres que les paramètres de type et les interfaces, et les recherches de membres dans les interfaces qui sont strictement à héritage simple (chaque interface dans la chaîne d’héritage a exactement zéro ou une interface de base directe), l’effet des règles de recherche est le suivant : simplement, les membres dérivés masquent les membres de base avec le même nom ou la même signature.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. Ces recherches à héritage unique ne sont jamais ambiguës.Such single-inheritance lookups are never ambiguous. Les ambiguïtés qui peuvent se produire à partir de recherches de membres dans des interfaces à héritage multiple sont décrites dans accès aux membres d’interface.The ambiguities that can possibly arise from member lookups in multiple-inheritance interfaces are described in Interface member access.

Types de baseBase types

Dans le cadre de la recherche de membres, un type T est considéré comme ayant les types de base suivants :For purposes of member lookup, a type T is considered to have the following base types:

  • Si T est object, T n’a pas de type de base.If T is object, then T has no base type.
  • Si T est un enum_type, les types de base de T sont les types de classe System.Enum, System.ValueType et object.If T is an enum_type, the base types of T are the class types System.Enum, System.ValueType, and object.
  • Si T est un struct_type, les types de base de T sont les types de classe System.ValueType et object.If T is a struct_type, the base types of T are the class types System.ValueType and object.
  • Si T est un class_type, les types de base de T sont les classes de base de T, y compris le type de classe object.If T is a class_type, the base types of T are the base classes of T, including the class type object.
  • Si T est un INTERFACE_TYPE, les types de base de T sont les interfaces de base de T et le type de classe object.If T is an interface_type, the base types of T are the base interfaces of T and the class type object.
  • Si T est un array_type, les types de base de T sont les types de classe System.Array et object.If T is an array_type, the base types of T are the class types System.Array and object.
  • Si T est un delegate_type, les types de base de T sont les types de classe System.Delegate et object.If T is a delegate_type, the base types of T are the class types System.Delegate and object.

Membres de fonctionFunction members

Les fonctions membres sont des membres qui contiennent des instructions exécutables.Function members are members that contain executable statements. Les membres de fonction sont toujours membres de types et ne peuvent pas être membres d’espaces de noms.Function members are always members of types and cannot be members of namespaces. C#définit les catégories suivantes de membres de fonction :C# defines the following categories of function members:

  • MéthodesMethods
  • PropertiesProperties
  • EventsEvents
  • IndexeursIndexers
  • Opérateurs définis par l’utilisateurUser-defined operators
  • Constructeurs d’instanceInstance constructors
  • Constructeurs statiquesStatic constructors
  • DestructeursDestructors

À l’exception des destructeurs et des constructeurs statiques (qui ne peuvent pas être appelés explicitement), les instructions contenues dans les fonctions membres sont exécutées par le biais d’appels de membres de fonction.Except for destructors and static constructors (which cannot be invoked explicitly), the statements contained in function members are executed through function member invocations. La syntaxe réelle pour l’écriture d’un appel de membre de fonction dépend de la catégorie de membre de fonction particulière.The actual syntax for writing a function member invocation depends on the particular function member category.

La liste d’arguments (listes d’arguments) d’un appel de membre de fonction fournit des valeurs réelles ou des références de variables pour les paramètres de la fonction membre.The argument list (Argument lists) of a function member invocation provides actual values or variable references for the parameters of the function member.

Les appels de méthodes génériques peuvent utiliser l’inférence de type pour déterminer le jeu d’arguments de type à passer à la méthode.Invocations of generic methods may employ type inference to determine the set of type arguments to pass to the method. Ce processus est décrit dans inférence de type.This process is described in Type inference.

Les appels de méthodes, d’indexeurs, d’opérateurs et de constructeurs d’instance utilisent la résolution de surcharge pour déterminer l’ensemble de candidats des membres de fonction à appeler.Invocations of methods, indexers, operators and instance constructors employ overload resolution to determine which of a candidate set of function members to invoke. Ce processus est décrit dans résolution de surcharge.This process is described in Overload resolution.

Une fois qu’un membre de fonction particulier a été identifié au moment de la liaison, éventuellement par la résolution de surcharge, le processus d’exécution réel de l’appel de la fonction membre est décrit dans vérification de la résolution de surcharge dynamique au momentde la compilation.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.

Le tableau suivant résume le traitement qui a lieu dans les constructions impliquant les six catégories de fonctions membres qui peuvent être explicitement appelées.The following table summarizes the processing that takes place in constructs involving the six categories of function members that can be explicitly invoked. Dans le tableau, e, x, y et value indiquent des expressions classées comme variables ou valeurs, T indique une expression classifiée comme un type, F est le nom simple d’une méthode et P est le nom simple d’une propriété.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.

ComposerConstruct ExempleExample DescriptionDescription
Appel de méthodeMethod invocation F(x,y) La résolution de surcharge est appliquée pour sélectionner la meilleure méthode F dans la classe ou le struct conteneur.Overload resolution is applied to select the best method F in the containing class or struct. La méthode est appelée avec la liste d’arguments (x,y).The method is invoked with the argument list (x,y). Si la méthode n’est pas static, l’expression d’instance est this.If the method is not static, the instance expression is this.
T.F(x,y) La résolution de surcharge est appliquée pour sélectionner la meilleure méthode F dans la classe ou le struct T.Overload resolution is applied to select the best method F in the class or struct T. Une erreur de liaison au moment de la liaison se produit si la méthode n’est pas static.A binding-time error occurs if the method is not static. La méthode est appelée avec la liste d’arguments (x,y).The method is invoked with the argument list (x,y).
e.F(x,y) La résolution de surcharge est appliquée pour sélectionner la meilleure méthode F dans la classe, la structure ou l’interface donnée par le type de e.Overload resolution is applied to select the best method F in the class, struct, or interface given by the type of e. Une erreur de liaison au moment de la liaison se produit si la méthode est static.A binding-time error occurs if the method is static. La méthode est appelée avec l’expression d’instance e et la liste d’arguments (x,y).The method is invoked with the instance expression e and the argument list (x,y).
Accès à la propriétéProperty access P L’accesseur get de la propriété P dans la classe ou le struct conteneur est appelé.The get accessor of the property P in the containing class or struct is invoked. Une erreur de compilation se produit si P est en écriture seule.A compile-time error occurs if P is write-only. Si P n’est pas static, l’expression d’instance est this.If P is not static, the instance expression is this.
P = value L’accesseur set de la propriété P dans la classe ou le struct conteneur est appelé avec la liste d’arguments (value).The set accessor of the property P in the containing class or struct is invoked with the argument list (value). Une erreur de compilation se produit si P est en lecture seule.A compile-time error occurs if P is read-only. Si P n’est pas static, l’expression d’instance est this.If P is not static, the instance expression is this.
T.P L’accesseur get de la propriété P dans la classe ou le struct T est appelé.The get accessor of the property P in the class or struct T is invoked. Une erreur de compilation se produit si P n’est pas static ou si P est en écriture seule.A compile-time error occurs if P is not static or if P is write-only.
T.P = value L’accesseur set de la propriété P dans la classe ou le struct T est appelé avec la liste d’arguments (value).The set accessor of the property P in the class or struct T is invoked with the argument list (value). Une erreur de compilation se produit si P n’est pas static ou si P est en lecture seule.A compile-time error occurs if P is not static or if P is read-only.
e.P L’accesseur get de la propriété P dans la classe, la structure ou l’interface donnée par le type de e est appelé avec l’expression d’instance 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. Une erreur de liaison s’est produite si P est static ou si P est en écriture seule.A binding-time error occurs if P is static or if P is write-only.
e.P = value L’accesseur set de la propriété P dans la classe, la structure ou l’interface donnée par le type de e est appelé avec l’expression d’instance e et la liste d’arguments (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). Une erreur de liaison s’est produite si P est static ou si P est en lecture seule.A binding-time error occurs if P is static or if P is read-only.
Accès aux événementsEvent access E += value L’accesseur add de l’événement E dans la classe ou le struct conteneur est appelé.The add accessor of the event E in the containing class or struct is invoked. Si E n’est pas statique, l’expression d’instance est this.If E is not static, the instance expression is this.
E -= value L’accesseur remove de l’événement E dans la classe ou le struct conteneur est appelé.The remove accessor of the event E in the containing class or struct is invoked. Si E n’est pas statique, l’expression d’instance est this.If E is not static, the instance expression is this.
T.E += value L’accesseur add de l’événement E dans la classe ou le struct T est appelé.The add accessor of the event E in the class or struct T is invoked. Une erreur de liaison au moment de la liaison se produit si E n’est pas statique.A binding-time error occurs if E is not static.
T.E -= value L’accesseur remove de l’événement E dans la classe ou le struct T est appelé.The remove accessor of the event E in the class or struct T is invoked. Une erreur de liaison au moment de la liaison se produit si E n’est pas statique.A binding-time error occurs if E is not static.
e.E += value L’accesseur add de l’événement E dans la classe, la structure ou l’interface donnée par le type de e est appelé avec l’expression d’instance 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. Une erreur de liaison au moment de la liaison se produit si E est statique.A binding-time error occurs if E is static.
e.E -= value L’accesseur remove de l’événement E dans la classe, la structure ou l’interface donnée par le type de e est appelé avec l’expression d’instance 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. Une erreur de liaison au moment de la liaison se produit si E est statique.A binding-time error occurs if E is static.
Accès aux indexeursIndexer access e[x,y] La résolution de surcharge est appliquée pour sélectionner le meilleur indexeur de la classe, du struct ou de l’interface donné par le type de e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. L’accesseur get de l’indexeur est appelé avec l’expression d’instance e et la liste d’arguments (x,y).The get accessor of the indexer is invoked with the instance expression e and the argument list (x,y). Une erreur de liaison au moment de la liaison se produit si l’indexeur est en écriture seule.A binding-time error occurs if the indexer is write-only.
e[x,y] = value La résolution de surcharge est appliquée pour sélectionner le meilleur indexeur de la classe, du struct ou de l’interface donné par le type de e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. L’accesseur set de l’indexeur est appelé avec l’expression d’instance e et la liste d’arguments (x,y,value).The set accessor of the indexer is invoked with the instance expression e and the argument list (x,y,value). Une erreur de liaison s’est produite si l’indexeur est en lecture seule.A binding-time error occurs if the indexer is read-only.
Appel d’opérateurOperator invocation -x La résolution de surcharge est appliquée pour sélectionner le meilleur opérateur unaire dans la classe ou le struct donné par le type de x.Overload resolution is applied to select the best unary operator in the class or struct given by the type of x. L’opérateur sélectionné est appelé avec la liste d’arguments (x).The selected operator is invoked with the argument list (x).
x + y La résolution de surcharge est appliquée pour sélectionner le meilleur opérateur binaire dans les classes ou les structs spécifiés par les types de x et y.Overload resolution is applied to select the best binary operator in the classes or structs given by the types of x and y. L’opérateur sélectionné est appelé avec la liste d’arguments (x,y).The selected operator is invoked with the argument list (x,y).
Appel du constructeur d’instanceInstance constructor invocation new T(x,y) La résolution de surcharge est appliquée pour sélectionner le constructeur d’instance le mieux adapté à la classe ou au struct T.Overload resolution is applied to select the best instance constructor in the class or struct T. Le constructeur d’instance est appelé avec la liste d’arguments (x,y).The instance constructor is invoked with the argument list (x,y).

Listes d’argumentsArgument lists

Chaque membre de fonction et appel de délégué inclut une liste d’arguments qui fournit des valeurs réelles ou des références de variables pour les paramètres de la fonction membre.Every function member and delegate invocation includes an argument list which provides actual values or variable references for the parameters of the function member. La syntaxe permettant de spécifier la liste d’arguments d’un appel de membre de fonction dépend de la catégorie de membre de fonction :The syntax for specifying the argument list of a function member invocation depends on the function member category:

  • Pour les constructeurs d’instance, les méthodes, les indexeurs et les délégués, les arguments sont spécifiés en tant que argument_list, comme décrit ci-dessous.For instance constructors, methods, indexers and delegates, the arguments are specified as an argument_list, as described below. Pour les indexeurs, lors de l’appel de l’accesseur set, la liste d’arguments comprend également l’expression spécifiée comme opérande droit de l’opérateur d’assignation.For indexers, when invoking the set accessor, the argument list additionally includes the expression specified as the right operand of the assignment operator.
  • Pour les propriétés, la liste d’arguments est vide lors de l’appel de l’accesseur get, et se compose de l’expression spécifiée comme opérande droit de l’opérateur d’assignation lors de l’appel de l’accesseur 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.
  • Pour les événements, la liste d’arguments se compose de l’expression spécifiée comme opérande droit de l’opérateur += ou -=.For events, the argument list consists of the expression specified as the right operand of the += or -= operator.
  • Pour les opérateurs définis par l’utilisateur, la liste d’arguments se compose du seul opérande de l’opérateur unaire ou des deux opérandes de l’opérateur binaire.For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator.

Les arguments des propriétés (Propriétés), événements (événements) et opérateurs définis par l’utilisateur (opérateurs) sont toujours passés en tant que paramètres de valeur (paramètres de valeur).The arguments of properties (Properties), events (Events), and user-defined operators (Operators) are always passed as value parameters (Value parameters). Les arguments des indexeurs (indexeurs) sont toujours passés en tant que paramètres de valeur (paramètres de valeur) ou tableaux de paramètres (tableaux de paramètres).The arguments of indexers (Indexers) are always passed as value parameters (Value parameters) or parameter arrays (Parameter arrays). Les paramètres de référence et de sortie ne sont pas pris en charge pour ces catégories de membres de fonction.Reference and output parameters are not supported for these categories of function members.

Les arguments d’un constructeur d’instance, d’une méthode, d’un indexeur ou d’un appel de délégué sont spécifiés en tant que argument_list: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
    ;

Un argument_list se compose d’un ou plusieurs arguments, séparés par des virgules.An argument_list consists of one or more arguments, separated by commas. Chaque argument se compose d’un argument_name facultatif suivi d’un argument_value.Each argument consists of an optional argument_name followed by an argument_value. Un argument avec un argument_name est désigné sous le nom d’argument nommé, alors qu’un argument sans argument_name est un argument positionnel.An argument with an argument_name is referred to as a named argument, whereas an argument without an argument_name is a positional argument. L’affichage d’un argument positionnel après un argument nommé dans un argument_listconstitue une erreur.It is an error for a positional argument to appear after a named argument in an argument_list.

Argument_value peut prendre l’une des formes suivantes :The argument_value can take one of the following forms:

  • Expressionindiquant que l’argument est passé en tant que paramètre de valeur (paramètres de valeur).An expression, indicating that the argument is passed as a value parameter (Value parameters).
  • Le mot clé ref suivi d’un variable_reference (références de variable), indiquant que l’argument est passé en tant que paramètre de référence (paramètres deréférence).The keyword ref followed by a variable_reference (Variable references), indicating that the argument is passed as a reference parameter (Reference parameters). Une variable doit être assignée de manière définitive (assignation définie) avant de pouvoir être passée en tant que paramètre de référence.A variable must be definitely assigned (Definite assignment) before it can be passed as a reference parameter. Le mot clé out suivi d’un variable_reference (références de variable), indiquant que l’argument est passé en tant que paramètre de sortie (paramètres desortie).The keyword out followed by a variable_reference (Variable references), indicating that the argument is passed as an output parameter (Output parameters). Une variable est considérée comme assignée définitivement (assignation définie) à la suite d’un appel de membre de fonction dans lequel la variable est passée comme paramètre de sortie.A variable is considered definitely assigned (Definite assignment) following a function member invocation in which the variable is passed as an output parameter.

Paramètres correspondantsCorresponding parameters

Pour chaque argument dans une liste d’arguments, il doit y avoir un paramètre correspondant dans le membre de fonction ou le délégué appelé.For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.

La liste de paramètres utilisée dans les éléments suivants est déterminée comme suit :The parameter list used in the following is determined as follows:

  • Pour les méthodes virtuelles et les indexeurs définis dans les classes, la liste de paramètres est choisie à partir de la déclaration ou de la substitution la plus spécifique, en commençant par le type statique du récepteur, et en recherchant dans ses classes de base.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.
  • Pour les méthodes d’interface et les indexeurs, la liste de paramètres est choisie en fonction de la définition la plus spécifique du membre, en commençant par le type d’interface et en parcourant les interfaces de base.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. Si aucune liste de paramètres unique n’est trouvée, une liste de paramètres avec des noms inaccessibles et aucun paramètre facultatif n’est construite, de sorte que les appels ne peuvent pas utiliser de paramètres nommés ou omettre des arguments facultatifs.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.
  • Pour les méthodes partielles, la liste de paramètres de la déclaration de méthode partielle de définition est utilisée.For partial methods, the parameter list of the defining partial method declaration is used.
  • Pour tous les autres membres de fonction et délégués, il n’existe qu’une seule liste de paramètres, qui est celle utilisée.For all other function members and delegates there is only a single parameter list, which is the one used.

La position d’un argument ou d’un paramètre est définie en tant que nombre d’arguments ou de paramètres qui la précèdent dans la liste d’arguments ou la liste de paramètres.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.

Les paramètres correspondants pour les arguments de membre de fonction sont établis comme suit :The corresponding parameters for function member arguments are established as follows:

  • Arguments dans le argument_list de constructeurs d’instance, de méthodes, d’indexeurs et de délégués :Arguments in the argument_list of instance constructors, methods, indexers and delegates:
    • Un argument positionnel dans lequel un paramètre fixe se produit à la même position dans la liste de paramètres correspond à ce paramètre.A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter.
    • Un argument positionnel d’un membre de fonction avec un tableau de paramètres appelé dans sa forme normale correspond au tableau de paramètres, qui doit se trouver à la même position dans la liste de paramètres.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.
    • Argument positionnel d’un membre de fonction avec un tableau de paramètres appelé dans sa forme développée, où aucun paramètre fixe ne se trouve à la même position dans la liste de paramètres, correspond à un élément dans le tableau de paramètres.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.
    • Un argument nommé correspond au paramètre du même nom dans la liste de paramètres.A named argument corresponds to the parameter of the same name in the parameter list.
    • Pour les indexeurs, lors de l’appel de l’accesseur set, l’expression spécifiée comme opérande droit de l’opérateur d’assignation correspond au paramètre value implicite de la déclaration d’accesseur 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.
  • Pour les propriétés, lors de l’appel de l’accesseur get, il n’y a pas d’arguments.For properties, when invoking the get accessor there are no arguments. Lors de l’appel de l’accesseur set, l’expression spécifiée comme opérande droit de l’opérateur d’assignation correspond au paramètre value implicite de la déclaration d’accesseur set.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.
  • Pour les opérateurs unaires définis par l’utilisateur (y compris les conversions), l’opérande unique correspond au paramètre unique de la déclaration d’opérateur.For user-defined unary operators (including conversions), the single operand corresponds to the single parameter of the operator declaration.
  • Pour les opérateurs binaires définis par l’utilisateur, l’opérande de gauche correspond au premier paramètre, tandis que l’opérande droit correspond au deuxième paramètre de la déclaration de l’opérateur.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.

Évaluation au moment de l’exécution des listes d’argumentsRun-time evaluation of argument lists

Pendant le traitement au moment de l’exécution d’un appel de membre de fonction (vérification au moment de la compilation de la résolution de surcharge dynamique), les expressions ou les références de variable d’une liste d’arguments sont évaluées dans l’ordre, de gauche à droite, comme suit :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:

  • Pour un paramètre de valeur, l’expression d’argument est évaluée et une conversion implicite (conversions implicites) en type de paramètre correspondant est effectuée.For a value parameter, the argument expression is evaluated and an implicit conversion (Implicit conversions) to the corresponding parameter type is performed. La valeur résultante devient la valeur initiale du paramètre de valeur dans l’appel de membre de fonction.The resulting value becomes the initial value of the value parameter in the function member invocation.
  • Pour un paramètre de référence ou de sortie, la référence de variable est évaluée et l’emplacement de stockage résultant devient l’emplacement de stockage représenté par le paramètre dans l’appel de membre de fonction.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. Si la référence variable donnée en tant que paramètre de référence ou de sortie est un élément de tableau d’un reference_type, un contrôle au moment de l’exécution est effectué pour garantir que le type d’élément du tableau est identique au type du paramètre.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. En cas d’échec de cette vérification, une System.ArrayTypeMismatchException est levée.If this check fails, a System.ArrayTypeMismatchException is thrown.

Les méthodes, les indexeurs et les constructeurs d’instance peuvent déclarer leur paramètre le plus à droite comme un tableau de paramètres (tableaux de paramètres).Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array (Parameter arrays). Ces fonctions sont appelées soit sous leur forme normale, soit sous leur forme développée en fonction de ce qui est applicable (fonction membre applicable) :Such function members are invoked either in their normal form or in their expanded form depending on which is applicable (Applicable function member):

  • Lorsqu’un membre de fonction avec un tableau de paramètres est appelé dans sa forme normale, l’argument donné pour le tableau de paramètres doit être une expression unique qui est implicitement convertible (conversions implicites) en type de tableau de paramètres.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. Dans ce cas, le tableau de paramètres agit précisément comme un paramètre de valeur.In this case, the parameter array acts precisely like a value parameter.
  • Lorsqu’un membre de fonction avec un tableau de paramètres est appelé dans sa forme développée, l’appel doit spécifier zéro, un ou plusieurs arguments positionnels pour le tableau de paramètres, où chaque argument est une expression implicitement convertible (conversions implicites). ) au type d’élément du tableau de paramètres.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. Dans ce cas, l’appel crée une instance du type de tableau de paramètres avec une longueur correspondant au nombre d’arguments, initialise les éléments de l’instance de tableau avec les valeurs d’argument données et utilise l’instance de tableau nouvellement créée comme 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.

Les expressions d’une liste d’arguments sont toujours évaluées dans l’ordre dans lequel elles sont écrites.The expressions of an argument list are always evaluated in the order they are written. Ainsi, l’exempleThus, 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++);
    }
}

génère la sortieproduces the output

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

Les règles de covariance de tableau (covariance de tableau) permettent à une valeur d’un type tableau A[] d’être une référence à une instance d’un type tableau B[], à condition qu’il existe une conversion de référence implicite de B en 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. En raison de ces règles, lorsqu’un élément de tableau d’un reference_type est passé en tant que paramètre de référence ou de sortie, un contrôle au moment de l’exécution est nécessaire pour garantir que le type d’élément réel du tableau est identique à celui du paramètre.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. Dans l’exempleIn 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
    }
}

le deuxième appel de F provoque la levée d’une System.ArrayTypeMismatchException, car le type d’élément réel de b est string et non 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.

Lorsqu’un membre de fonction avec un tableau de paramètres est appelé dans sa forme développée, l’appel est traité exactement comme si une expression de création de tableau avec un initialiseur de tableau (expressions de création de tableau) a été insérée autour des paramètres développés.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. Par exemple, étant donné la déclarationFor example, given the declaration

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

les appels suivants de la forme développée de la méthodethe following invocations of the expanded form of the method

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

correspondre exactement àcorrespond exactly to

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

En particulier, Notez qu’un tableau vide est créé lorsqu’il n’y a aucun argument donné pour le tableau de paramètres.In particular, note that an empty array is created when there are zero arguments given for the parameter array.

Lorsque des arguments sont omis d’un membre de fonction avec des paramètres facultatifs correspondants, les arguments par défaut de la déclaration de membre de fonction sont passés implicitement.When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. Étant donné qu’elles sont toujours constantes, leur évaluation n’aura pas d’impact sur l’ordre d’évaluation des arguments restants.Because these are always constant, their evaluation will not impact the evaluation order of the remaining arguments.

Inférence de typeType inference

Quand une méthode générique est appelée sans spécifier d’arguments de type, un processus d' inférence de type tente de déduire des arguments de type pour l’appel.When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. La présence de l’inférence de type permet d’utiliser une syntaxe plus pratique pour appeler une méthode générique et permet au programmeur d’éviter de spécifier des informations de type redondantes.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. Par exemple, à partir de la déclaration de méthode :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;
    }
}

Il est possible d’appeler la méthode Choose sans spécifier explicitement un argument de type :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>

Par le biais de l’inférence de type, les arguments de type int et string sont déterminés à partir des arguments à la méthode.Through type inference, the type arguments int and string are determined from the arguments to the method.

L’inférence de type se produit dans le cadre du traitement au moment de la liaison d’un appel de méthode (appel de méthode) et a lieu avant l’étape de résolution de surcharge de l’appel.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. Lorsqu’un groupe de méthodes particulier est spécifié dans un appel de méthode et qu’aucun argument de type n’est spécifié dans le cadre de l’appel de méthode, l’inférence de type est appliquée à chaque méthode générique dans le groupe de méthodes.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. Si l’inférence de type est réussie, les arguments de type déduits sont utilisés pour déterminer les types d’arguments pour la résolution de surcharge suivante.If type inference succeeds, then the inferred type arguments are used to determine the types of arguments for subsequent overload resolution. Si la résolution de surcharge choisit une méthode générique comme une méthode à appeler, les arguments de type inférés sont utilisés en tant qu’arguments de type réels pour l’appel.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. Si l’inférence de type pour une méthode particulière échoue, cette méthode ne participe pas à la résolution de surcharge.If type inference for a particular method fails, that method does not participate in overload resolution. L’échec de l’inférence de type, en soi-même, ne provoque pas d’erreur au moment de la liaison.The failure of type inference, in and of itself, does not cause a binding-time error. Toutefois, il arrive souvent à une erreur de liaison lorsque la résolution de surcharge ne parvient pas à trouver les méthodes applicables.However, it often leads to a binding-time error when overload resolution then fails to find any applicable methods.

Si le nombre d’arguments fourni est différent du nombre de paramètres dans la méthode, l’inférence échoue immédiatement.If the supplied number of arguments is different than the number of parameters in the method, then inference immediately fails. Dans le cas contraire, supposez que la méthode générique possède la signature suivante :Otherwise, assume that the generic method has the following signature:

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

Avec un appel de méthode de la forme M(E1...Em), la tâche de l’inférence de type consiste à trouver des arguments de type uniques S1...Sn pour chacun des paramètres de type X1...Xn afin que l’appel M<S1...Sn>(E1...Em) devienne valide.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.

Pendant le processus d’inférence, chaque paramètre de type Xi est fixé à un type particulier Si ou non résolu avec un ensemble de limitesassociées.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. Chaque limite est de type T.Each of the bounds is some type T. Initialement, chaque variable de type Xi n’est pas corrigée avec un ensemble de limites vide.Initially each type variable Xi is unfixed with an empty set of bounds.

L’inférence de type a lieu en plusieurs phases.Type inference takes place in phases. Chaque phase essaiera de déduire les arguments de type pour d’autres variables de type en fonction des résultats de la phase précédente.Each phase will try to infer type arguments for more type variables based on the findings of the previous phase. La première phase effectue quelques inférences initiales des limites, tandis que la deuxième phase résout des variables de type à des types spécifiques et déduit d’autres limites.The first phase makes some initial inferences of bounds, whereas the second phase fixes type variables to specific types and infers further bounds. La deuxième phase peut être répétée plusieurs fois.The second phase may have to be repeated a number of times.

Remarque : L’inférence de type a lieu non seulement quand une méthode générique est appelée.Note: Type inference takes place not only when a generic method is called. L’inférence de type pour la conversion de groupes de méthodes est décrite dans inférence de type pour la conversion de groupes de méthodes et la recherche du meilleur type commun d’un ensemble d’expressions est décrite dans recherche du meilleur type commun d’un ensemble d’expressions.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.

La première phaseThe first phase

Pour chacun des arguments de méthode Ei :For each of the method arguments Ei:

  • Si Ei est une fonction anonyme, une inférence de type de paramètre explicite (inférences de type de paramètre explicite) est effectuée de Ei à TiIf Ei is an anonymous function, an explicit parameter type inference (Explicit parameter type inferences) is made from Ei to Ti
  • Sinon, si Ei a un type U et xi est un paramètre de valeur, une inférence à la limite inférieure est effectuée de U à 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.
  • Sinon, si Ei a un type U et xi est un paramètre ref ou out, une inférence exacte est faite de U à 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.
  • Sinon, aucune inférence n’est effectuée pour cet argument.Otherwise, no inference is made for this argument.

La deuxième phaseThe second phase

La deuxième phase se déroule comme suit :The second phase proceeds as follows:

  • Toutes les variables de type non fixed Xi qui ne dépendent pas (dépendance) tout Xj sont fixes (Correction).All unfixed type variables Xi which do not depend on (Dependence) any Xj are fixed (Fixing).
  • S’il n’existe pas de telles variables de type, toutes les variables de type non fixed Xi sont fixes pour lesquelles tous les éléments suivants sont détenus :If no such type variables exist, all unfixed type variables Xi are fixed for which all of the following hold:
    • Il existe au moins une variable de type Xj qui dépend de XiThere is at least one type variable Xj that depends on Xi
    • Xi a un ensemble non vide de limitesXi has a non-empty set of bounds
  • S’il n’existe aucune variable de type de ce type et qu’il existe encore des variables de type non fixes , l’inférence de type échoue.If no such type variables exist and there are still unfixed type variables, type inference fails.
  • Sinon, s’il n’existe aucune variable de type non fixe , l’inférence de type est réussie.Otherwise, if no further unfixed type variables exist, type inference succeeds.
  • Sinon, pour tous les arguments Ei avec le type Ti de paramètre correspondant où les types de sortie (types de sortie) contiennent des variables Xj de type non fixes, mais pas les types d’entrée (types d’entrée), l’inférence de type de sortie (inférences de type de sortie) est effectuée de Ei à 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. La deuxième phase est ensuite répétée.Then the second phase is repeated.

Types d’entréeInput types

Si E est un groupe de méthodes ou une fonction anonyme implicitement typée et que T est un type délégué ou un type d’arborescence d’expression, tous les types de paramètres de T sont des types d’entrée de E avec le type 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.

Types de sortieOutput types

Si E est un groupe de méthodes ou une fonction anonyme et que T est un type délégué ou un type d’arborescence d’expression, le type de retour de T est un type de sortie de E avec le type 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.

DépendanceDependence

Une variable de type non fixe Xi dépend directement d' une variable de type non fixe Xj si pour un argument Ek avec le type Tk Xj se produit dans un type d’entrée de Ek avec le type Tk et 0 se produit dans un type de sortie de 2 avec le type 3.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.

Xj dépend de Xi si Xj dépend directement de Xi ou si Xi dépend directement de Xk et Xk dépend de 1.Xj depends on Xi if Xj depends directly on Xi or if Xi depends directly on Xk and Xk depends on Xj. Par conséquent, « dépend de » est la fermeture transitive mais non réflexive de « dépend directement de ».Thus "depends on" is the transitive but not reflexive closure of "depends directly on".

Inférences de type de sortieOutput type inferences

Une inférence de type de sortie est effectuée d' une expression E à un type T de la manière suivante :An output type inference is made from an expression E to a type T in the following way:

  • Si E est une fonction anonyme avec un type de retour déduit U (type de retour déduit) et T est un type délégué ou un type d’arborescence d’expression avec le type de retour Tb, puis une inférence à la limite inférieure (inférences à liaison inférieure) est effectué de U à 0.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.
  • Sinon, si E est un groupe de méthodes et que T est un type délégué ou un type d’arborescence d’expression avec des types de paramètres T1...Tk et le type de retour Tb, et que la résolution de surcharge de E avec les types T1...Tk produit une méthode unique avec le type de retour U , une inférence de liaison inférieure est effectuée de U à 1.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.
  • Sinon, si E est une expression de type U, une inférence de liaison inférieure est effectuée de U à T.Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T.
  • Dans le cas contraire, aucune inférence n’est effectuée.Otherwise, no inferences are made.

Inférences de type de paramètre explicitesExplicit parameter type inferences

Une inférence de type de paramètre explicite est effectuée à partir d’une expression E vers un type T de la façon suivante :An explicit parameter type inference is made from an expression E to a type T in the following way:

  • Si E est une fonction anonyme explicitement typée avec des types de paramètres U1...Uk et T est un type délégué ou un type d’arborescence d’expression avec des types de paramètres V1...Vk, puis pour chaque Ui une inférence exacte (inférences exactes) est effectuée entre Ui et les 0 correspondants.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.

Inférences exactesExact inferences

Une inférence exacte d' un type U à un type V est effectuée comme suit :An exact inference from a type U to a type V is made as follows:

  • Si V est l’un des @no__t non fixes -2, U est ajouté au jeu de limites exactes pour Xi.If V is one of the unfixed Xi then U is added to the set of exact bounds for Xi.

  • Sinon, définit V1...Vk et U1...Uk sont déterminés en vérifiant si l’un des cas suivants s’applique :Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • V est un type de tableau V1[...] et U est un type de tableau U1[...] du même rangV is an array type V1[...] and U is an array type U1[...] of the same rank
    • V est le type V1? et U est le type U1?V is the type V1? and U is the type U1?
    • V est un type construit C<V1...Vk>and U est un type construit C<U1...Uk>V is a constructed type C<V1...Vk>and U is a constructed type C<U1...Uk>

    Si l’un de ces cas s’applique, une inférence exacte est effectuée à partir de chaque Ui vers le Vi correspondant.If any of these cases apply then an exact inference is made from each Ui to the corresponding Vi.

  • Sinon, aucune inférence n’est effectuée.Otherwise no inferences are made.

Inférences à limite inférieureLower-bound inferences

Une inférence de liaison inférieure d' un type U à un type V est effectuée comme suit :A lower-bound inference from a type U to a type V is made as follows:

  • Si V est l’un des @no__t non fixes -2, U est ajouté au jeu de limites inférieures pour Xi.If V is one of the unfixed Xi then U is added to the set of lower bounds for Xi.

  • Sinon, si V est le type V1?and U est le type U1?, une inférence de limite inférieure est apportée de U1 à 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.

  • Sinon, définit U1...Uk et V1...Vk sont déterminés en vérifiant si l’un des cas suivants s’applique :Otherwise, sets U1...Uk and V1...Vk are determined by checking if any of the following cases apply:

    • V est un type de tableau V1[...] et U est un type de tableau U1[...] (ou un paramètre de type dont le type de base effectif est U1[...]) du même rangV 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 est l’un des IEnumerable<V1>, ICollection<V1> ou IList<V1> et U est un type de tableau unidimensionnel U1[] (ou un paramètre de type dont le type de base effectif est 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 est une classe, un struct, une interface ou un type délégué construit C<V1...Vk> et il existe un type unique C<U1...Uk> tel que U (ou, si U est un paramètre de type, sa classe de base effective ou tout membre de son ensemble d’interfaces effectif) est identique à , hérite de (directement ou indirectement), ou implémente (directement ou indirectement) 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>.

      (La restriction « unicité » signifie que dans l’interface de cas C<T> {} class U: C<X>, C<Y> {}, aucune inférence n’est effectuée lors de la déduction de U à C<T>, car U1 peut être X ou 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.)

    Si l’un de ces cas s’applique, une inférence est effectuée à partir de chaque Ui vers le Vi correspondant comme suit :If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Si Ui n’est pas connu comme étant un type référence, une inférence exacte est effectuéeIf Ui is not known to be a reference type then an exact inference is made
    • Sinon, si U est un type tableau, une inférence de liaison inférieure est effectuéeOtherwise, if U is an array type then a lower-bound inference is made
    • Sinon, si V est C<V1...Vk>, l’inférence dépend du paramètre de type i-Th de C :Otherwise, if V is C<V1...Vk> then inference depends on the i-th type parameter of C:
      • S’il s’agit d’un covariant, une inférence de liaison inférieure est effectuée.If it is covariant then a lower-bound inference is made.
      • S’il est contravariant, une inférence de la limite supérieure est effectuée.If it is contravariant then an upper-bound inference is made.
      • S’il s’agit d’un invariant, une inférence exacte est effectuée.If it is invariant then an exact inference is made.
  • Dans le cas contraire, aucune inférence n’est effectuée.Otherwise, no inferences are made.

Inférences à la limite supérieureUpper-bound inferences

Une inférence à la limite supérieure d' un type U à un type V est effectuée comme suit :An upper-bound inference from a type U to a type V is made as follows:

  • Si V est l’un des @no__t non fixes -2, U est ajouté au jeu de limites supérieures pour Xi.If V is one of the unfixed Xi then U is added to the set of upper bounds for Xi.

  • Sinon, définit V1...Vk et U1...Uk sont déterminés en vérifiant si l’un des cas suivants s’applique :Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • U est un type de tableau U1[...] et V est un type de tableau V1[...] du même rangU is an array type U1[...] and V is an array type V1[...] of the same rank

    • U est l’un des IEnumerable<Ue>, ICollection<Ue> ou IList<Ue> et V est un type de tableau unidimensionnel Ve[]U is one of IEnumerable<Ue>, ICollection<Ue> or IList<Ue> and V is a one-dimensional array type Ve[]

    • U est le type U1? et V est le type V1?U is the type U1? and V is the type V1?

    • U est construit classe, struct, interface ou type délégué C<U1...Uk> et V est une classe, un struct, une interface ou un type délégué qui est identique à, hérite de (directement ou indirectement), ou implémente (directement ou indirectement) un type unique 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>

      (La restriction d’unicité signifie que si nous avons interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}, aucune inférence n’est effectuée lors de la déduction de 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>. Les inférences ne sont pas apportées de U1 à X<Q> ou Y<Q>.)Inferences are not made from U1 to either X<Q> or Y<Q>.)

    Si l’un de ces cas s’applique, une inférence est effectuée à partir de chaque Ui vers le Vi correspondant comme suit :If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Si Ui n’est pas connu comme étant un type référence, une inférence exacte est effectuéeIf Ui is not known to be a reference type then an exact inference is made
    • Sinon, si V est un type tableau, une inférence à la limite supérieure est effectuéeOtherwise, if V is an array type then an upper-bound inference is made
    • Sinon, si U est C<U1...Uk>, l’inférence dépend du paramètre de type i-Th de C :Otherwise, if U is C<U1...Uk> then inference depends on the i-th type parameter of C:
      • S’il s’agit d’un covariant, une inférence de la limite supérieure est effectuée.If it is covariant then an upper-bound inference is made.
      • S’il est contravariant, une inférence de liaison inférieure est effectuée.If it is contravariant then a lower-bound inference is made.
      • S’il s’agit d’un invariant, une inférence exacte est effectuée.If it is invariant then an exact inference is made.
  • Dans le cas contraire, aucune inférence n’est effectuée.Otherwise, no inferences are made.

RésolutionFixing

Une variable de type non fixe Xi avec un ensemble de limites est fixe comme suit :An unfixed type variable Xi with a set of bounds is fixed as follows:

  • L’ensemble des types candidats Uj démarre en tant que jeu de tous les types dans le jeu de limites pour Xi.The set of candidate types Uj starts out as the set of all types in the set of bounds for Xi.
  • Nous examinons ensuite chaque limite pour Xi à son tour : Pour chaque type exact U de Xi tous les types Uj qui ne sont pas identiques à U sont supprimés du jeu de candidats.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. Pour chaque limite inférieure U de Xi tous les types Uj pour lesquels il n’existe pas de conversion implicite de U sont supprimés du jeu de candidats.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. Pour chaque limite supérieure U de Xi tous les types Uj à partir desquels il n’existe pas de conversion implicite en U sont supprimés du jeu de candidats.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.
  • Si parmi les types candidats restants Uj, il existe un type unique V à partir duquel il existe une conversion implicite vers tous les autres types candidats, alors Xi est fixé à 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.
  • Sinon, l’inférence de type échoue.Otherwise, type inference fails.

Type de retour déduitInferred return type

Le type de retour déduit d’une fonction anonyme F est utilisé pendant l’inférence de type et la résolution de surcharge.The inferred return type of an anonymous function F is used during type inference and overload resolution. Le type de retour déduit ne peut être déterminé que pour une fonction anonyme dans laquelle tous les types de paramètre sont connus, soit parce qu’ils sont explicitement donnés, fournis par le biais d’une conversion de fonction anonyme ou déduits pendant l’inférence de type sur un générique englobant appel de méthode.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.

Le type de résultat inféré est déterminé comme suit :The inferred result type is determined as follows:

  • Si le corps de F est une expression qui a un type, le type de résultat déduit de F est le type de cette expression.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.
  • Si le corps de F est un bloc et que l’ensemble d’expressions dans les instructions return du bloc a un type le mieux courant T (enrecherchant le meilleur type commun d’un ensemble d’expressions), le type de résultat inféré de F est 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.
  • Dans le cas contraire, un type de résultat ne peut pas être déduit pour F.Otherwise, a result type cannot be inferred for F.

Le type de retour déduit est déterminé comme suit :The inferred return type is determined as follows:

  • Si F est Async et que le corps de F est une expression classée comme Nothing (classifications d’expression), ou un bloc d’instructions où aucune instruction return n’a d’expressions, le type de retour déduit est 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
  • Si F est asynchrone et a un type de résultat déduit T, le type de retour déduit est 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>.
  • Si F est non asynchrone et a un type de résultat déduit T, le type de retour déduit est T.If F is non-async and has an inferred result type T, the inferred return type is T.
  • Sinon, un type de retour ne peut pas être déduit pour F.Otherwise a return type cannot be inferred for F.

En guise d’exemple d’inférence de type impliquant des fonctions anonymes, considérez la méthode d’extension Select déclarée dans la classe 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);
        }
    }
}

En supposant que l’espace de noms System.Linq a été importé avec une clause using et une classe Customer avec une propriété Name de type string, la méthode Select peut être utilisée pour sélectionner les noms d’une liste de clients :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);

L’appel de méthode d’extension (appel de méthode d’extension) de Select est traité en réécrivant l’appel dans un appel de méthode statique :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);

Étant donné que les arguments de type n’ont pas été spécifiés explicitement, l’inférence de type est utilisée pour déduire les arguments de type.Since type arguments were not explicitly specified, type inference is used to infer the type arguments. Tout d’abord, l’argument customers est lié au paramètre source, ce qui déduit T Customer.First, the customers argument is related to the source parameter, inferring T to be Customer. Ensuite, à l’aide du processus d’inférence de type de fonction anonyme décrit ci-dessus, c reçoit le type Customer, et l’expression c.Name est liée au type de retour du paramètre selector, en déduisant S pour être string.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. Ainsi, l’appel est équivalent àThus, the invocation is equivalent to

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

et le résultat est de type IEnumerable<string>.and the result is of type IEnumerable<string>.

L’exemple suivant montre comment l’inférence de type de fonction anonyme permet aux informations de type de « circuler » entre les arguments dans un appel de méthode générique.The following example demonstrates how anonymous function type inference allows type information to "flow" between arguments in a generic method invocation. À partir de la méthode :Given the method:

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

Inférence de type pour l’appel :Type inference for the invocation:

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

se déroule comme suit : Tout d’abord, l’argument "1:15:30" est lié au paramètre value, ce qui déduit X string.proceeds as follows: First, the argument "1:15:30" is related to the value parameter, inferring X to be string. Ensuite, le paramètre de la première fonction anonyme, s, reçoit le type déduit string, et l’expression TimeSpan.Parse(s) est liée au type de retour de f1, ce qui déduit Y comme 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. Enfin, le paramètre de la deuxième fonction anonyme, t, reçoit le type déduit System.TimeSpan, et l’expression t.TotalSeconds est liée au type de retour de f2, ce qui déduit Z comme 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. Ainsi, le résultat de l’appel est de type double.Thus, the result of the invocation is of type double.

Inférence de type pour la conversion de groupes de méthodesType inference for conversion of method groups

Comme pour les appels de méthodes génériques, l’inférence de type doit également être appliquée quand un groupe de méthodes M qui contient une méthode générique est converti en un type délégué donné D (conversions de groupe de méthodes).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). Pour une méthode donnéeGiven a method

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

et le groupe de méthodes M sont assignés au type délégué D la tâche de l’inférence de type consiste à rechercher des arguments de type S1...Sn afin que l’expression :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>

devient compatible (déclarations déléguées) avec D.becomes compatible (Delegate declarations) with D.

Contrairement à l’algorithme d’inférence de type pour les appels de méthode générique, dans ce cas, il n’y a que des typesd’arguments, aucune expressiond’argument.Unlike the type inference algorithm for generic method calls, in this case there are only argument types, no argument expressions. En particulier, il n’y a pas de fonctions anonymes et, par conséquent, n’a pas besoin de plusieurs phases d’inférence.In particular, there are no anonymous functions and hence no need for multiple phases of inference.

Au lieu de cela, tous les Xi sont considérés comme non résoluset une inférence de liaison inférieure est effectuée à partir de chaque type d’argument Uj de D vers le type de paramètre correspondant Tj de 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. Si pour l’une des Xi aucune limite n’a été trouvée, l’inférence de type échoue.If for any of the Xi no bounds were found, type inference fails. Sinon, tous les Xi sont résolus en Si correspondantes, qui sont le résultat de l’inférence de type.Otherwise, all Xi are fixed to corresponding Si, which are the result of type inference.

Recherche du meilleur type commun d’un ensemble d’expressionsFinding the best common type of a set of expressions

Dans certains cas, un type commun doit être déduit pour un ensemble d’expressions.In some cases, a common type needs to be inferred for a set of expressions. En particulier, les types d’éléments des tableaux implicitement typés et les types de retour des fonctions anonymes avec des corps de bloc sont détectés de cette façon.In particular, the element types of implicitly typed arrays and the return types of anonymous functions with block bodies are found in this way.

Intuitivement, étant donné un ensemble d’expressions E1...Em, cette inférence doit être équivalente à l’appel d’une méthodeIntuitively, given a set of expressions E1...Em this inference should be equivalent to calling a method

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

avec la Ei comme arguments.with the Ei as arguments.

Plus précisément, l’inférence commence par une variable de type non fixe X.More precisely, the inference starts out with an unfixed type variable X. Les inférences de type de sortie sont ensuite effectuées de chaque Ei à X.Output type inferences are then made from each Ei to X. Enfin, X est fixe et, en cas de réussite, le type résultant S est le meilleur type commun qui en résulte pour les expressions.Finally, X is fixed and, if successful, the resulting type S is the resulting best common type for the expressions. S’il n’existe pas de S, les expressions n’ont pas le meilleur type commun.If no such S exists, the expressions have no best common type.

Résolution de surchargeOverload resolution

La résolution de surcharge est un mécanisme de liaison-temps permettant de sélectionner le meilleur membre de fonction à appeler à partir d’une liste d’arguments et d’un jeu de membres de fonction candidats.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. La résolution de surcharge sélectionne la fonction membre à appeler dans les contextes suivants C#dans :Overload resolution selects the function member to invoke in the following distinct contexts within C#:

Chacun de ces contextes définit l’ensemble des membres de fonction candidats et la liste d’arguments de manière unique, comme décrit en détail dans les sections répertoriées ci-dessus.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. Par exemple, l’ensemble de candidats pour un appel de méthode n’inclut pas les méthodes marquées override (recherche de membre), et les méthodes d’une classe de base ne sont pas candidates si une méthode dans une classe dérivée est applicable (appels de méthode).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).

Une fois que les membres de la fonction candidate et la liste d’arguments ont été identifiés, la sélection du meilleur membre de la fonction est la même dans tous les cas :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:

  • Compte tenu de l’ensemble des fonctions membres candidates applicables, le meilleur membre de fonction de cet ensemble est localisé.Given the set of applicable candidate function members, the best function member in that set is located. Si le jeu contient un seul membre de fonction, ce membre de fonction est le meilleur membre de fonction.If the set contains only one function member, then that function member is the best function member. Dans le cas contraire, le meilleur membre de fonction est le membre de fonction qui est mieux que tous les autres membres de fonction par rapport à la liste d’arguments donnée, à condition que chaque membre de fonction soit comparé à tous les autres membres de fonction utilisant les règles dans une meilleure fonction membre.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. S’il n’y a pas exactement un membre de fonction qui est mieux que tous les autres membres de fonction, l’appel de membre de fonction est ambigu et une erreur de liaison s’est produite.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.

Les sections suivantes définissent les significations exactes des termes du membre de fonction applicable et du meilleur membre de fonction.The following sections define the exact meanings of the terms applicable function member and better function member.

Membre de fonction applicableApplicable function member

Un membre de fonction est considéré comme un membre de fonction applicable en ce qui concerne une liste d’arguments A lorsque toutes les conditions suivantes sont vraies :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:

  • Chaque argument de A correspond à un paramètre dans la déclaration de membre de fonction comme décrit dans les paramètres correspondants, et tout paramètre auquel aucun argument correspond est un paramètre facultatif.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.
  • Pour chaque argument dans A, le mode de passage de paramètre de l’argument (c’est-à-dire, valeur, ref ou out) est identique au mode de passage de paramètre du paramètre correspondant, etFor 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
    • pour un paramètre de valeur ou un tableau de paramètres, une conversion implicite (conversions implicites) existe à partir de l’argument vers le type du paramètre correspondant, oufor a value parameter or a parameter array, an implicit conversion (Implicit conversions) exists from the argument to the type of the corresponding parameter, or
    • pour un paramètre ref ou out, le type de l’argument est identique au type du paramètre correspondant.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter. Après tout, un paramètre ref ou out est un alias pour l’argument passé.After all, a ref or out parameter is an alias for the argument passed.

Pour un membre de fonction qui comprend un tableau de paramètres, si le membre de fonction est applicable par les règles ci-dessus, il est dit s’il est applicable dans sa forme normale.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. Si un membre de fonction qui comprend un tableau de paramètres n’est pas applicable dans sa forme normale, la fonction membre peut à la place être applicable dans sa forme développée: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:

  • La forme développée est construite en remplaçant le tableau de paramètres dans la déclaration de membre de fonction par zéro ou plusieurs paramètres de valeur du type d’élément du tableau de paramètres, de telle sorte que le nombre d’arguments dans la liste d’arguments A corresponde au nombre total de paramètres.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. Si A a moins d’arguments que le nombre de paramètres fixes dans la déclaration de membre de fonction, la forme développée de la fonction membre ne peut pas être construite et n’est donc pas applicable.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.
  • Dans le cas contraire, la forme développée s’applique si pour chaque argument dans A le mode de passage du paramètre de l’argument est identique au mode de passage du paramètre du paramètre correspondant, etOtherwise, 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
    • pour un paramètre de valeur fixe ou un paramètre de valeur créé par l’expansion, une conversion implicite (conversions implicites) existe à partir du type de l’argument vers le type du paramètre correspondant, oufor 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
    • pour un paramètre ref ou out, le type de l’argument est identique au type du paramètre correspondant.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter.

Meilleure fonction membreBetter function member

Pour déterminer le meilleur membre de la fonction, une liste d’arguments tronquée a est construite, contenant uniquement les expressions d’arguments, dans l’ordre dans lequel elles apparaissent dans la liste d’arguments d’origine.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.

Les listes de paramètres pour chacun des fonctions candidates sont construites de la façon suivante :Parameter lists for each of the candidate function members are constructed in the following way:

  • Le formulaire développé est utilisé si le membre de fonction ne s’applique qu’au formulaire développé.The expanded form is used if the function member was applicable only in the expanded form.
  • Les paramètres facultatifs sans arguments correspondants sont supprimés de la liste de paramètresOptional parameters with no corresponding arguments are removed from the parameter list
  • Les paramètres sont réorganisés afin qu’ils se produisent à la même position que l’argument correspondant dans la liste d’arguments.The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.

À partir d’une liste d’arguments A avec un ensemble d’expressions d’argument {E1, E2, ..., En} et deux membres de fonction applicables Mp et Mq avec des types de paramètres {P1, P2, ..., Pn} et {Q1, Q2, ..., Qn}, Mp est défini comme étant une meilleure fonction membre que Mq siGiven 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

  • pour chaque argument, la conversion implicite de Ex en Qx n’est pas meilleure que la conversion implicite de Ex en Px, etfor each argument, the implicit conversion from Ex to Qx is not better than the implicit conversion from Ex to Px, and
  • pour au moins un argument, la conversion de Ex en Px est meilleure que la conversion de Ex en Qx.for at least one argument, the conversion from Ex to Px is better than the conversion from Ex to Qx.

Lorsque vous effectuez cette évaluation, si Mp ou Mq est applicable dans sa forme développée, Px ou Qx fait référence à un paramètre dans la forme développée de la liste de paramètres.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.

Si les séquences de type de paramètre @ no__t-0 et {Q1, Q2, ..., Qn} sont équivalentes (c’est-à-dire que chaque Pi a une conversion d’identité vers le Qi correspondant), les règles de rupture suivantes sont appliquées, dans l’ordre, pour déterminer le meilleur membre de fonction.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.

  • Si Mp est une méthode non générique et que Mq est une méthode générique, Mp est préférable à Mq.If Mp is a non-generic method and Mq is a generic method, then Mp is better than Mq.
  • Sinon, si Mp est applicable dans sa forme normale et que Mq a un tableau params et s’applique uniquement dans sa forme développée, Mp est préférable à 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.
  • Sinon, si Mp a plus de paramètres déclarés que Mq, Mp est préférable à Mq.Otherwise, if Mp has more declared parameters than Mq, then Mp is better than Mq. Cela peut se produire si les deux méthodes ont des tableaux params et s’appliquent uniquement à leurs formes développées.This can occur if both methods have params arrays and are applicable only in their expanded forms.
  • Sinon, si tous les paramètres de Mp ont un argument correspondant, alors que les arguments par défaut doivent être remplacés par au moins un paramètre facultatif dans Mq, Mp est préférable à 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.
  • Sinon, si Mp a des types de paramètres plus spécifiques que Mq, Mp est préférable à Mq.Otherwise, if Mp has more specific parameter types than Mq, then Mp is better than Mq. Laissez {R1, R2, ..., Rn} et {S1, S2, ..., Sn} représentent les types de paramètres non instanciés et non développés de Mp et Mq.Let {R1, R2, ..., Rn} and {S1, S2, ..., Sn} represent the uninstantiated and unexpanded parameter types of Mp and Mq. les types de paramètres de Mp sont plus spécifiques que Mq si, pour chaque paramètre, Rx n’est pas moins spécifique que Sx, et, pour au moins un paramètre, Rx est plus spécifique que 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:
    • Un paramètre de type est moins spécifique qu’un paramètre de non-type.A type parameter is less specific than a non-type parameter.
    • De manière récursive, un type construit est plus spécifique qu’un autre type construit (avec le même nombre d’arguments de type) si au moins un argument de type est plus spécifique et qu’aucun argument de type n’est moins spécifique que l’argument de type correspondant dans l’autre.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.
    • Un type tableau est plus spécifique qu’un autre type tableau (avec le même nombre de dimensions) si le type d’élément du premier est plus spécifique que le type d’élément du second.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.
  • Dans le cas contraire, si un membre est un opérateur non levé et que l’autre est un opérateur levé, la meilleure est la meilleure.Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.
  • Dans le cas contraire, aucune des fonctions membres n’est meilleure.Otherwise, neither function member is better.

Meilleure conversion à partir de l’expressionBetter conversion from expression

Dans le cas d’une conversion implicite C1 qui convertit une expression E en type T1, et une conversion implicite C2 qui convertit une expression E en un type T2, C1 est une meilleure conversion que C2 si @no__ t-9 ne correspond pas exactement à 0 et au moins l’un des éléments suivants :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:

Expression correspondant exactementExactly matching Expression

À partir d’une expression E et d’un type T, E correspond exactement à T Si l’un des éléments suivants est présent :Given an expression E and a type T, E exactly matches T if one of the following holds:

  • E a un type S, et une conversion d’identité existe entre S et TE has a type S, and an identity conversion exists from S to T
  • E est une fonction anonyme, T est soit un type délégué D, soit un type d’arborescence d’expression Expression<D> et l’un des éléments suivants :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:
    • Un type de retour déduit X existe pour E dans le contexte de la liste de paramètres de D (type de retour déduit) et une conversion d’identité existe entre le X et le type de retour de 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
    • @No__t-0 est non asynchrone et D a un type de retour Y ou E est asynchrone et D a un type de retour Task<Y>, et l’un des éléments suivants :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:
      • Le corps de E est une expression qui correspond exactement à YThe body of E is an expression that exactly matches Y
      • Le corps de E est un bloc d’instruction où chaque instruction return retourne une expression qui correspond exactement à YThe body of E is a statement block where every return statement returns an expression that exactly matches Y

Meilleure cible de conversionBetter conversion target

Étant donné deux types différents T1 et T2, T1 est une meilleure cible de conversion que T2 Si aucune conversion implicite de T2 en T1 n’existe, et au moins l’un des éléments suivants :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:

  • Une conversion implicite de T1 en T2 existeAn implicit conversion from T1 to T2 exists
  • T1 est un type délégué D1 ou un type d’arborescence d’expression Expression<D1>, T2 est soit un type délégué D2, soit un type d’arborescence d’expression Expression<D2>, D1 a un type de retour S1 et l’un des éléments suivants :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 est un retour voidD2 is void returning
    • D2 a un type de retour S2, et S1 est une meilleure cible de conversion que S2D2 has a return type S2, and S1 is a better conversion target than S2
  • T1 est Task<S1>, T2 est Task<S2>, et S1 est une meilleure cible de conversion que S2T1 is Task<S1>, T2 is Task<S2>, and S1 is a better conversion target than S2
  • T1 est S1 ou S1?S1 est un type intégral signé, et T2 est S2 ou S2?, où S2 est un type intégral non signé.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. Plus précisément :Specifically:
    • S1 est sbyte et S2 est byte, ushort, uint ou ulongS1 is sbyte and S2 is byte, ushort, uint, or ulong
    • S1 est short et S2 est ushort, uint ou ulongS1 is short and S2 is ushort, uint, or ulong
    • S1 est int et S2 est uint ou ulongS1 is int and S2 is uint, or ulong
    • S1 est long et S2 est ulongS1 is long and S2 is ulong

Surcharge dans les classes génériquesOverloading in generic classes

Tandis que les signatures telles qu’elles sont déclarées doivent être uniques, il est possible que la substitution des arguments de type génère des signatures identiques.While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. Dans ce cas, les règles de résolution de surcharge ci-dessus sélectionnent le membre le plus spécifique.In such cases, the tie-breaking rules of overload resolution above will pick the most specific member.

Les exemples suivants montrent des surcharges qui sont valides et non valides conformément à cette règle :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);
}

Vérification de la résolution de surcharge dynamique au moment de la compilationCompile-time checking of dynamic overload resolution

Pour la plupart des opérations liées de manière dynamique, l’ensemble des candidats possibles pour la résolution est inconnu au moment de la compilation.For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. Dans certains cas, toutefois, l’ensemble de candidats est connu au moment de la compilation :In certain cases, however the candidate set is known at compile-time:

  • Appels de méthode statiques avec des arguments dynamiquesStatic method calls with dynamic arguments
  • Appels de méthode d’instance où le récepteur n’est pas une expression dynamiqueInstance method calls where the receiver is not a dynamic expression
  • Appels de l’indexeur où le récepteur n’est pas une expression dynamiqueIndexer calls where the receiver is not a dynamic expression
  • Appels de constructeur avec des arguments dynamiquesConstructor calls with dynamic arguments

Dans ces cas, un contrôle limité au moment de la compilation est effectué pour chaque candidat afin de déterminer si l’un d’eux peut éventuellement s’appliquer au moment de l’exécution. Cette vérification se compose des étapes suivantes :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:

  • Inférence de type partiel : Tout argument de type qui ne dépend pas directement ou indirectement d’un argument de type dynamic est déduit à l’aide des règles d' inférence de type.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. Les arguments de type restants sont inconnus.The remaining type arguments are unknown.
  • Vérification de l’applicabilité partielle : L’applicabilité est vérifiée en fonction du membre de fonction applicable, mais ignore les paramètres dont les types sont inconnus.Partial applicability check: Applicability is checked according to Applicable function member, but ignoring parameters whose types are unknown.
  • Si aucun candidat ne réussit ce test, une erreur de compilation se produit.If no candidate passes this test, a compile-time error occurs.

Appel de membre de fonctionFunction member invocation

Cette section décrit le processus qui a lieu au moment de l’exécution pour appeler un membre de fonction particulier.This section describes the process that takes place at run-time to invoke a particular function member. Il est supposé qu’un processus de liaison a déjà déterminé le membre particulier à appeler, éventuellement en appliquant la résolution de surcharge à un ensemble de membres de fonction candidats.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.

Dans le cadre de la description du processus d’appel, les membres de fonction sont divisés en deux catégories :For purposes of describing the invocation process, function members are divided into two categories:

  • Fonctions membres statiques.Static function members. Il s’agit des constructeurs d’instance, des méthodes statiques, des accesseurs de propriété statique et des opérateurs définis par l’utilisateur.These are instance constructors, static methods, static property accessors, and user-defined operators. Les fonctions membres statiques sont toujours non virtuelles.Static function members are always non-virtual.
  • Membres de fonction d’instance.Instance function members. Il s’agit des méthodes d’instance, des accesseurs de propriété d’instance et des accesseurs d’indexeurs.These are instance methods, instance property accessors, and indexer accessors. Les fonctions membres de fonction d’instance sont non virtuelles ou virtuelles et sont toujours appelées sur une instance particulière.Instance function members are either non-virtual or virtual, and are always invoked on a particular instance. L’instance est calculée par une expression d’instance et devient accessible dans le membre de fonction en tant que this (cet accès).The instance is computed by an instance expression, and it becomes accessible within the function member as this (This access).

Le traitement au moment de l’exécution d’un appel de membre de fonction se compose des étapes suivantes, où M est la fonction membre et, si M est un membre d’instance, E est l’expression d’instance :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:

  • Si M est un membre de fonction statique :If M is a static function member:

    • La liste d’arguments est évaluée comme décrit dans listes d’arguments.The argument list is evaluated as described in Argument lists.
    • M est appelée.M is invoked.
  • Si M est un membre de fonction d’instance déclaré dans un Value_type:If M is an instance function member declared in a value_type:

    • E est évalué.E is evaluated. Si cette évaluation provoque une exception, aucune autre étape n’est exécutée.If this evaluation causes an exception, then no further steps are executed.
    • Si E n’est pas classée en tant que variable, une variable locale temporaire de type E est créée et la valeur de E est assignée à cette variable.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 est ensuite reclassifiée comme une référence à cette variable locale temporaire.E is then reclassified as a reference to that temporary local variable. La variable temporaire est accessible en tant que this dans M, mais pas de quelque manière que ce soit.The temporary variable is accessible as this within M, but not in any other way. Ainsi, uniquement lorsque E est une véritable variable, l’appelant peut observer les modifications apportées par M à this.Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.
    • La liste d’arguments est évaluée comme décrit dans listes d’arguments.The argument list is evaluated as described in Argument lists.
    • M est appelée.M is invoked. La variable référencée par E devient la variable référencée par this.The variable referenced by E becomes the variable referenced by this.
  • Si M est un membre de fonction d’instance déclaré dans un reference_type:If M is an instance function member declared in a reference_type:

    • E est évalué.E is evaluated. Si cette évaluation provoque une exception, aucune autre étape n’est exécutée.If this evaluation causes an exception, then no further steps are executed.
    • La liste d’arguments est évaluée comme décrit dans listes d’arguments.The argument list is evaluated as described in Argument lists.
    • Si le type de E est un Value_type, une conversion boxing (conversions boxing) est effectuée pour convertir E en type object, et E est considéré comme étant de type object dans les étapes suivantes.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. Dans ce cas, M ne peut être qu’un membre de System.Object.In this case, M could only be a member of System.Object.
    • La valeur de E est vérifiée comme valide.The value of E is checked to be valid. Si la valeur de E est null, une System.NullReferenceException est levée et aucune autre étape n’est exécutée.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • L’implémentation de la fonction membre à appeler est déterminée :The function member implementation to invoke is determined:
      • Si le type au moment de la liaison de E est une interface, la fonction membre à appeler est l’implémentation de M fournie par le type au moment de l’exécution de l’instance référencée par 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. Cette fonction membre est déterminée en appliquant les règles de mappage d’interface (mappage d’interface) pour déterminer l’implémentation de M fournie par le type au moment de l’exécution de l’instance référencée par 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.
      • Sinon, si M est un membre de fonction virtuelle, la fonction membre à appeler est l’implémentation de M fournie par le type au moment de l’exécution de l’instance référencée par 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. Cette fonction membre est déterminée en appliquant les règles de détermination de l’implémentation la plus dérivée (méthodes virtuelles) de M en ce qui concerne le type au moment de l’exécution de l’instance référencée par 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.
      • Dans le cas contraire, M est un membre de fonction non virtuel, et la fonction membre à appeler est M lui-même.Otherwise, M is a non-virtual function member, and the function member to invoke is M itself.
    • L’implémentation de la fonction membre déterminée à l’étape ci-dessus est appelée.The function member implementation determined in the step above is invoked. L’objet référencé par E devient l’objet référencé par this.The object referenced by E becomes the object referenced by this.

Appels sur les instances boxedInvocations on boxed instances

Un membre de fonction implémenté dans un Value_type peut être appelé via une instance boxed de ce Value_type dans les cas suivants :A function member implemented in a value_type can be invoked through a boxed instance of that value_type in the following situations:

  • Quand la fonction membre est un override d’une méthode héritée du type object et est appelée via une expression d’instance de type 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.
  • Quand la fonction membre est une implémentation d’un membre de fonction d’interface et qu’elle est appelée par le biais d’une expression d’instance d’un INTERFACE_TYPE.When the function member is an implementation of an interface function member and is invoked through an instance expression of an interface_type.
  • Quand la fonction membre est appelée par l’intermédiaire d’un délégué.When the function member is invoked through a delegate.

Dans ces situations, l’instance boxed est considérée comme contenant une variable de Value_type, et cette variable devient la variable référencée par this dans l’appel de membre de fonction.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. En particulier, cela signifie que lorsqu’un membre de fonction est appelé sur une instance boxed, la fonction membre peut modifier la valeur contenue dans l’instance boxed.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.

Expressions primairesPrimary expressions

Les expressions primaires incluent les formes les plus simples des expressions.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
    ;

Les expressions primaires sont réparties entre array_creation_expressions et primary_no_array_creation_expressions.Primary expressions are divided between array_creation_expressions and primary_no_array_creation_expressions. Le traitement de l’expression de création de tableau de cette manière, plutôt que son affichage avec les autres formulaires d’expression simples, permet à la grammaire d’interdire le code potentiellement confus, tel queTreating 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];

qui, autrement, serait interprété commewhich would otherwise be interpreted as

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

LittérauxLiterals

Un primary_expression qui se compose d’un littéral (littéraux) est classé comme une valeur.A primary_expression that consists of a literal (Literals) is classified as a value.

Chaînes interpoléesInterpolated strings

Un interpolated_string_expression se compose d’un signe $ suivi d’un littéral de chaîne normal ou Verbatim, où les trous, délimités par { et }, encadrent les expressions et les spécifications de mise en forme.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. Une expression de chaîne interpolée est le résultat d’un interpolated_string_literal qui a été divisé en jetons individuels, comme décrit dans littéraux de chaîne interpolés.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)+
    ;

Le constant_expression d’une interpolation doit avoir une conversion implicite en int.The constant_expression in an interpolation must have an implicit conversion to int.

Un interpolated_string_expression est classé comme une valeur.An interpolated_string_expression is classified as a value. Si elle est immédiatement convertie en System.IFormattable ou System.FormattableString avec une conversion de chaîne interpolée implicite (conversions de chaînes interpolées implicites), l’expression de chaîne interpolée a ce type.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. Dans le cas contraire, il a le type string.Otherwise, it has the type string.

Si le type d’une chaîne interpolée est System.IFormattable ou System.FormattableString, la signification est un appel à 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. Si le type est string, la signification de l’expression est un appel à string.Format.If the type is string, the meaning of the expression is a call to string.Format. Dans les deux cas, la liste d’arguments de l’appel se compose d’un littéral de chaîne de format avec des espaces réservés pour chaque interpolation, et d’un argument pour chaque expression qui correspond aux espaces réservés.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.

Le littéral de chaîne de format est construit comme suit, où N est le nombre d’interpolations dans interpolated_string_expression:The format string literal is constructed as follows, where N is the number of interpolations in the interpolated_string_expression:

  • Si un interpolated_regular_string_whole ou un interpolated_verbatim_string_whole suit le signe $, le littéral de chaîne de format est ce jeton.If an interpolated_regular_string_whole or an interpolated_verbatim_string_whole follows the $ sign, then the format string literal is that token.
  • Dans le cas contraire, le littéral de chaîne de format se compose des éléments suivants :Otherwise, the format string literal consists of:
    • Premier interpolated_regular_string_start ou interpolated_verbatim_string_startFirst the interpolated_regular_string_start or interpolated_verbatim_string_start
    • Puis, pour chaque nombre I de 0 à N-1 :Then for each number I from 0 to N-1:
      • Représentation décimale de IThe decimal representation of I
      • Ensuite, si l' interpolation correspondante a un constant_expression, un , (virgule) suivi de la représentation décimale de la valeur de constant_expressionThen, if the corresponding interpolation has a constant_expression, a , (comma) followed by the decimal representation of the value of the constant_expression
      • Ensuite, interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid ou interpolated_verbatim_string_end suivent immédiatement l’interpolation correspondante.Then the interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid or interpolated_verbatim_string_end immediately following the corresponding interpolation.

Les arguments suivants sont simplement les expressions des interpolations (le cas échéant), dans l’ordre.The subsequent arguments are simply the expressions from the interpolations (if any), in order.

TODO : exemples.TODO: examples.

Noms simplesSimple names

Un simple_name se compose d’un identificateur, éventuellement suivi d’une liste d’arguments de type :A simple_name consists of an identifier, optionally followed by a type argument list:

simple_name
    : identifier type_argument_list?
    ;

Un simple_name se présente sous la forme I ou sous la forme I<A1,...,Ak>, où I est un identificateur unique et <A1,...,Ak> est un type_argument_listfacultatif.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. Si aucun type_argument_list n’est spécifié, envisagez K pour être égal à zéro.When no type_argument_list is specified, consider K to be zero. Le simple_name est évalué et classé comme suit :The simple_name is evaluated and classified as follows:

  • Si K est égal à zéro et que le simple_name apparaît dans un bloc et si l’espace de déclaration de variable locale (déclarations) du bloc(ou du blocenglobant) contient une variable locale, un paramètre ou une constante avec Name @ no__t-6, alors le simple_name fait référence à cette variable locale, à un paramètre ou à une constante, et est classée comme une variable ou une valeur.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.

  • Si K est égal à zéro et que le simple_name apparaît dans le corps d’une déclaration de méthode générique et si cette déclaration comprend un paramètre de type portant le nom @ no__t-2, le simple_name fait référence à ce paramètre de type.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.

  • Sinon, pour chaque type d’instance @ no__t-0 (type d’instance), en commençant par le type d’instance de la déclaration de type englobante immédiate et en continuant avec le type d’instance de chaque classe englobante ou déclaration de struct (le cas échéant) :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):

    • Si K est égal à zéro et que la déclaration de T comprend un paramètre de type nommé @ no__t-2, le simple_name fait référence à ce paramètre de type.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.
    • Sinon, si une recherche de membre (recherche de membre) de I dans T avec les arguments K @ no__t-4Type produit une correspondance :Otherwise, if a member lookup (Member lookup) of I in T with K type arguments produces a match:
      • Si T est le type d’instance du type de classe ou de struct immédiatement englobant et que la recherche identifie une ou plusieurs méthodes, le résultat est un groupe de méthodes avec une expression d’instance associée de 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. Si une liste d’arguments de type a été spécifiée, elle est utilisée pour appeler une méthode générique (appels de méthode).If a type argument list was specified, it is used in calling a generic method (Method invocations).
      • Sinon, si T est le type d’instance du type de classe ou de struct immédiatement englobant, si la recherche identifie un membre d’instance et si la référence se produit dans le corps d’un constructeur d’instance, d’une méthode d’instance ou d’un accesseur d’instance, le résultat est le même qu’un accès de membre (accès aux membres) de la forme 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. Cela peut se produire uniquement lorsque K est égal à zéro.This can only happen when K is zero.
      • Dans le cas contraire, le résultat est le même qu’un accès de membre (accès aux membres) de la forme T.I ou 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>. Dans ce cas, il s’agit d’une erreur de liaison au moment de la liaison pour que le simple_name fasse référence à un membre d’instance.In this case, it is a binding-time error for the simple_name to refer to an instance member.
  • Sinon, pour chaque espace de noms @ no__t-0, en commençant par l’espace de noms dans lequel le simple_name se produit, en continuant avec chaque espace de noms englobant (le cas échéant) et en terminant par l’espace de noms global, les étapes suivantes sont évaluées jusqu’à ce qu’une entité soit localisée :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:

    • Si K est égal à zéro et que I est le nom d’un espace de noms dans @ no__t-2, alors :If K is zero and I is the name of a namespace in N, then:
      • Si l’emplacement où le simple_name se produit est entouré d’une déclaration d’espace de noms pour N et que la déclaration d’espace de noms contient un extern_alias_directive ou using_alias_directive qui associe le nom @ no__t-4 à un espace de noms ou type, le simple_name est ambigu et une erreur de compilation se produit.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.
      • Sinon, simple_name fait référence à l’espace de noms nommé I dans N.Otherwise, the simple_name refers to the namespace named I in N.
    • Sinon, si N contient un type accessible avec les paramètres Name @ no__t-1 et K @ no__t-3Type, alors :Otherwise, if N contains an accessible type having name I and K type parameters, then:
      • Si K est égal à zéro et que l’emplacement où le simple_name se produit est entouré d’une déclaration d’espace de noms pour N et que la déclaration d’espace de noms contient un extern_alias_directive ou using_alias_directive qui associe nom @ no__t-5 avec un espace de noms ou un type, alors le simple_name est ambigu et une erreur de compilation se produit.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.
      • Sinon, namespace_or_type_name fait référence au type construit avec les arguments de type donnés.Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
    • Sinon, si l’emplacement où le simple_name se produit est entouré d’une déclaration d’espace de noms pour @ no__t-1 :Otherwise, if the location where the simple_name occurs is enclosed by a namespace declaration for N:
      • Si K est égal à zéro et que la déclaration d’espace de noms contient un extern_alias_directive ou un using_alias_directive qui associe le nom @ no__t-3 à un espace de noms ou un type importé, le simple_name fait référence à cet espace de noms ou entrer.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.
      • Sinon, si les espaces de noms et les déclarations de type importés par les using_namespace_directiveet using_static_directives de la déclaration d’espace de noms contiennent exactement un type accessible ou un membre statique sans extension nommé @ no__ les paramètres t-2 et K @ no__t-4Type, le simple_name fait référence à ce type ou membre construit avec les arguments de type donnés.Otherwise, if the namespaces and type declarations imported by the using_namespace_directives and using_static_directives 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.
      • Sinon, si les espaces de noms et les types importés par les using_namespace_directivesde la déclaration d’espace de noms contiennent plusieurs types accessibles ou un membre statique de méthode non-extension ayant les paramètres Name @ no__t-1 et K @ no__t-3Type, le simple_name est alors ambigu et une erreur se produit.Otherwise, if the namespaces and types imported by the using_namespace_directives 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.

    Notez que cette étape entière est exactement parallèle à l’étape correspondante dans le traitement d’un namespace_or_type_name (espace de noms et noms de type).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).

  • Dans le cas contraire, le simple_name n’est pas défini et une erreur de compilation se produit.Otherwise, the simple_name is undefined and a compile-time error occurs.

Expressions entre parenthèsesParenthesized expressions

Un parenthesized_expression se compose d’une expression placée entre parenthèses.A parenthesized_expression consists of an expression enclosed in parentheses.

parenthesized_expression
    : '(' expression ')'
    ;

Un parenthesized_expression est évalué en évaluant l' expression entre parenthèses.A parenthesized_expression is evaluated by evaluating the expression within the parentheses. Si l' expression entre parenthèses désigne un espace de noms ou un type, une erreur de compilation se produit.If the expression within the parentheses denotes a namespace or type, a compile-time error occurs. Dans le cas contraire, le résultat de l' parenthesized_expression est le résultat de l’évaluation de l' expressioncontenue.Otherwise, the result of the parenthesized_expression is the result of the evaluation of the contained expression.

Accès au membreMember access

Un member_access se compose d’un primary_expression, d’un predefined_typeou d’un qualified_alias_member, suivi d’un jeton « . », suivi d’un identificateur, éventuellement suivi d’un 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'
    ;

La production qualified_alias_member est définie dans les qualificateurs d’alias d’espace de noms.The qualified_alias_member production is defined in Namespace alias qualifiers.

Un member_access se présente sous la forme E.I ou sous la forme E.I<A1, ..., Ak>, où E est une expression primaire, I est un identificateur unique et <A1, ..., Ak> est un type_argument_listfacultatif.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. Si aucun type_argument_list n’est spécifié, envisagez K pour être égal à zéro.When no type_argument_list is specified, consider K to be zero.

Un member_access avec un primary_expression de type dynamic est lié dynamiquement (liaison dynamique).A member_access with a primary_expression of type dynamic is dynamically bound (Dynamic binding). Dans ce cas, le compilateur classe l’accès au membre comme un accès à la propriété de type dynamic.In this case the compiler classifies the member access as a property access of type dynamic. Les règles ci-dessous pour déterminer la signification des member_access sont ensuite appliquées au moment de l’exécution, à l’aide du type au moment de l’exécution et non du type au moment de la compilation du 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. Si la classification au moment de l’exécution débouche sur un groupe de méthodes, l’accès au membre doit être le primary_expression d’un invocation_expression.If this run-time classification leads to a method group, then the member access must be the primary_expression of an invocation_expression.

Le member_access est évalué et classé comme suit :The member_access is evaluated and classified as follows:

  • Si K est égal à zéro et que E est un espace de noms et que E contient un espace de noms imbriqué nommé @ no__t-3, le résultat est cet espace de noms.If K is zero and E is a namespace and E contains a nested namespace with name I, then the result is that namespace.
  • Sinon, si E est un espace de noms et que E contient un type accessible avec les paramètres Name @ no__t-2 et K @ no__t-4Type, le résultat est ce type construit avec les arguments de type donnés.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.
  • Si E est un predefined_type ou un primary_expression classé comme type, si E n’est pas un paramètre de type, et si une recherche de membre (recherche de membre) de I dans E avec les paramètres K @ no__t-8Type produit une correspondance, E.I est ensuite évaluée et classée comme suit :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:
    • Si I identifie un type, le résultat est ce type construit avec les arguments de type donnés.If I identifies a type, then the result is that type constructed with the given type arguments.
    • Si I identifie une ou plusieurs méthodes, le résultat est un groupe de méthodes sans expression d’instance associée.If I identifies one or more methods, then the result is a method group with no associated instance expression. Si une liste d’arguments de type a été spécifiée, elle est utilisée pour appeler une méthode générique (appels de méthode).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Si I identifie une propriété static, le résultat est un accès à une propriété sans expression d’instance associée.If I identifies a static property, then the result is a property access with no associated instance expression.
    • Si I identifie un champ static :If I identifies a static field:
      • Si le champ est readonly et que la référence se produit à l’extérieur du constructeur statique de la classe ou du struct dans lequel le champ est déclaré, le résultat est une valeur, à savoir la valeur du champ statique @ no__t-1 dans @ no__t-2.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.
      • Dans le cas contraire, le résultat est une variable, à savoir le champ statique @ no__t-0 dans @ no__t-1.Otherwise, the result is a variable, namely the static field I in E.
    • Si I identifie un événement static :If I identifies a static event:
      • Si la référence se produit dans la classe ou le struct dans lequel l’événement est déclaré, et si l’événement a été déclaré sans event_accessor_declarations (Events), E.I est traité exactement comme si I était un champ statique.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.
      • Dans le cas contraire, le résultat est un accès à un événement sans expression d’instance associée.Otherwise, the result is an event access with no associated instance expression.
    • Si I identifie une constante, le résultat est une valeur, à savoir la valeur de cette constante.If I identifies a constant, then the result is a value, namely the value of that constant.
    • Si I identifie un membre de l’énumération, le résultat est une valeur, à savoir la valeur de ce membre de l’énumération.If I identifies an enumeration member, then the result is a value, namely the value of that enumeration member.
    • Dans le cas contraire, E.I est une référence de membre non valide et une erreur de compilation se produit.Otherwise, E.I is an invalid member reference, and a compile-time error occurs.
  • Si E est un accès à une propriété, un accès à un indexeur, une variable ou une valeur, le type de qui est @ no__t-1 et une recherche de membre (recherche de membre) de I dans T avec les arguments K @ no__t-6Type produisent une correspondance, puis E.I est évaluée et classé comme suit :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:
    • Tout d’abord, si E est un accès à une propriété ou un indexeur, la valeur de la propriété ou de l’indexeur est obtenue (valeurs des expressions) et E est reclassifié comme une valeur.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.
    • Si I identifie une ou plusieurs méthodes, le résultat est un groupe de méthodes avec une expression d’instance associée de E.If I identifies one or more methods, then the result is a method group with an associated instance expression of E. Si une liste d’arguments de type a été spécifiée, elle est utilisée pour appeler une méthode générique (appels de méthode).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Si I identifie une propriété d’instance,If I identifies an instance property,
      • Si E est this, I identifie une propriété implémentée automatiquement (Propriétés implémentées automatiquement) sans méthode setter, et la référence se produit dans un constructeur d’instance pour une classe ou un type struct T, le résultat est une variable, à savoir le champ de stockage masqué pour la propriété automatique spécifiée par I dans l’instance de T donnée par 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.
      • Dans le cas contraire, le résultat est un accès à une propriété avec une expression d’instance associée de @ no__t-0.Otherwise, the result is a property access with an associated instance expression of E.
    • Si T est un class_type et I identifie un champ d’instance de ce class_type:If T is a class_type and I identifies an instance field of that class_type:
      • Si la valeur de E est null, une System.NullReferenceException est levée.If the value of E is null, then a System.NullReferenceException is thrown.
      • Sinon, si le champ est readonly et que la référence se produit en dehors d’un constructeur d’instance de la classe dans laquelle le champ est déclaré, le résultat est une valeur, à savoir la valeur du champ @ no__t-1 dans l’objet référencé par @ no__t-2.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.
      • Dans le cas contraire, le résultat est une variable, à savoir le champ @ no__t-0 dans l’objet référencé par @ no__t-1.Otherwise, the result is a variable, namely the field I in the object referenced by E.
    • Si T est un struct_type et I identifie un champ d’instance de ce struct_type:If T is a struct_type and I identifies an instance field of that struct_type:
      • Si E est une valeur, ou si le champ est readonly et que la référence se produit en dehors d’un constructeur d’instance du struct dans lequel le champ est déclaré, le résultat est une valeur, à savoir la valeur du champ @ no__t-2 dans l’instance de struct donnée par @ no__t-3.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.
      • Dans le cas contraire, le résultat est une variable, à savoir le champ @ no__t-0 dans l’instance de struct donnée par @ no__t-1.Otherwise, the result is a variable, namely the field I in the struct instance given by E.
    • Si I identifie un événement d’instance :If I identifies an instance event:
      • Si la référence se produit dans la classe ou le struct dans lequel l’événement est déclaré, et si l’événement a été déclaré sans event_accessor_declarations (événements) et si la référence ne se produit pas comme la partie gauche d’un opérateur += ou -= , E.I est traité exactement comme si I était un champ d’instance.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.
      • Dans le cas contraire, le résultat est un accès aux événements avec une expression d’instance associée de @ no__t-0.Otherwise, the result is an event access with an associated instance expression of E.
  • Sinon, une tentative est faite pour traiter E.I comme un appel de méthode d’extension (appels de méthode d’extension).Otherwise, an attempt is made to process E.I as an extension method invocation (Extension method invocations). En cas d’échec, E.I est une référence de membre non valide et une erreur de liaison au moment de la liaison se produit.If this fails, E.I is an invalid member reference, and a binding-time error occurs.

Noms simples et noms de types identiquesIdentical simple names and type names

Dans un accès aux membres de la forme E.I, si E est un identificateur unique et si la signification de E comme simple_name (noms simples) est une constante, un champ, une propriété, une variable locale ou un paramètre avec le même type que la signification de E comme une type_name (espace de noms et nom de type), les deux significations possibles de E sont autorisées.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. Les deux significations possibles de E.I ne sont jamais ambiguës, étant donné que I doit nécessairement être membre du type E dans les deux cas.The two possible meanings of E.I are never ambiguous, since I must necessarily be a member of the type E in both cases. En d’autres termes, la règle autorise simplement l’accès aux membres statiques et aux types imbriqués de E là où une erreur de compilation se produirait autrement.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. Exemple :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
    }
}

Ambiguïtés grammaticalesGrammar ambiguities

Les productions pour simple_name (noms simples) et member_access (accès aux membres) peuvent donner lieu à des ambiguïtés dans la grammaire des expressions.The productions for simple_name (Simple names) and member_access (Member access) can give rise to ambiguities in the grammar for expressions. Par exemple, l’instruction suivante :For example, the statement:

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

peut être interprété comme un appel à F avec deux arguments, G < A et B > (7).could be interpreted as a call to F with two arguments, G < A and B > (7). Elle peut également être interprétée comme un appel à F avec un argument, qui est un appel à une méthode générique @ no__t-1 avec deux arguments de type et un argument normal.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.

Si une séquence de jetons peut être analysée (en contexte) en tant que simple_name (noms simples), member_access (accès aux membres) ou pointer_member_access (accès aux membres du pointeur) se terminant par un type_argument_ List (arguments de type), le jeton qui suit immédiatement le jeton > de fermeture est examiné.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. S’il s’agit de l’un desIf it is one of

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

le type_argument_list est ensuite conservé dans le cadre de simple_name, member_access ou pointer_member_access et toute autre analyse possible de la séquence de jetons est ignorée.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. Dans le cas contraire, le type_argument_list n’est pas considéré comme faisant partie de simple_name, member_access ou pointer_member_access, même s’il n’y a pas d’autre analyse possible de la séquence de jetons.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. Notez que ces règles ne sont pas appliquées lors de l’analyse d’un type_argument_list dans un namespace_or_type_name (noms de type et d’espacede noms).Note that these rules are not applied when parsing a type_argument_list in a namespace_or_type_name (Namespace and type names). L'instructionThe statement

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

sera, selon cette règle, interprété comme un appel à F avec un argument, qui est un appel à une méthode générique G avec deux arguments de type et un argument normal.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. Les instructionsThe statements

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

est interprété comme un appel à F avec deux arguments.will each be interpreted as a call to F with two arguments. L'instructionThe statement

x = F < A > +y;

est interprété comme un opérateur inférieur à, supérieur à et opérateur unaire plus, comme si l’instruction avait été écrite x = (F < A) > (+y), au lieu d’être simple_name avec un type_argument_list suivi d’un opérateur binaire plus.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. Dans l’instructionIn the statement

x = y is C<T> + z;

les jetons C<T> sont interprétés comme un namespace_or_type_name avec un type_argument_list.the tokens C<T> are interpreted as a namespace_or_type_name with a type_argument_list.

Appel d’expressionsInvocation expressions

Un invocation_expression est utilisé pour appeler une méthode.An invocation_expression is used to invoke a method.

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

Un invocation_expression est lié dynamiquement (liaison dynamique) si au moins l’un des éléments suivants est présent :An invocation_expression is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Le primary_expression a un type au moment de la compilation dynamic.The primary_expression has compile-time type dynamic.
  • Au moins un argument du argument_list facultatif a le type au moment de la compilation dynamic et le primary_expression n’a pas de type délégué.At least one argument of the optional argument_list has compile-time type dynamic and the primary_expression does not have a delegate type.

Dans ce cas, le compilateur classe invocation_expression en tant que valeur de type dynamic.In this case the compiler classifies the invocation_expression as a value of type dynamic. Les règles ci-dessous pour déterminer la signification des invocation_expression sont ensuite appliquées au moment de l’exécution, à l’aide du type au moment de l’exécution et non du type au moment de la compilation de celles du primary_expression et des arguments ayant le type au moment de la compilation @no_ _ t-2.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. Si le primary_expression n’a pas le type au moment de la compilation dynamic, l’appel de la méthode subit une vérification limitée au moment de la compilation, comme décrit dans contrôle de la résolution de surcharge dynamique au moment de la compilation.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.

Le primary_expression d’un invocation_expression doit être un groupe de méthodes ou une valeur d’un delegate_type.The primary_expression of an invocation_expression must be a method group or a value of a delegate_type. Si le primary_expression est un groupe de méthodes, le invocation_expression est un appel de méthode (appel de méthode).If the primary_expression is a method group, the invocation_expression is a method invocation (Method invocations). Si primary_expression est une valeur d’un delegate_type, invocation_expression est un appel de délégué (appel dedélégué).If the primary_expression is a value of a delegate_type, the invocation_expression is a delegate invocation (Delegate invocations). Si primary_expression n’est ni un groupe de méthodes ni une valeur d’un delegate_type, une erreur de liaison s’est produite.If the primary_expression is neither a method group nor a value of a delegate_type, a binding-time error occurs.

Le argument_list facultatif (listes d’arguments) fournit des valeurs ou des références de variable pour les paramètres de la méthode.The optional argument_list (Argument lists) provides values or variable references for the parameters of the method.

Le résultat de l’évaluation d’un invocation_expression est classé comme suit :The result of evaluating an invocation_expression is classified as follows:

  • Si le invocation_expression appelle une méthode ou un délégué qui retourne void, le résultat est Nothing.If the invocation_expression invokes a method or delegate that returns void, the result is nothing. Une expression classifiée comme Nothing n’est autorisée que dans le contexte d’un statement_expression (instructions d’expression) ou en tant que corps d’un lambda_expression (expressions de fonction anonymes).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). Sinon, une erreur de temps de liaison se produit.Otherwise a binding-time error occurs.
  • Dans le cas contraire, le résultat est une valeur du type retourné par la méthode ou le délégué.Otherwise, the result is a value of the type returned by the method or delegate.

Appels de méthodeMethod invocations

Pour un appel de méthode, le primary_expression du invocation_expression doit être un groupe de méthodes.For a method invocation, the primary_expression of the invocation_expression must be a method group. Le groupe de méthodes identifie la méthode à appeler ou l’ensemble de méthodes surchargées à partir desquelles choisir une méthode spécifique à appeler.The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke. Dans ce dernier cas, la détermination de la méthode spécifique à appeler est basée sur le contexte fourni par les types des arguments dans le argument_list.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.

Le traitement au moment de la liaison d’un appel de méthode au format M(A), où M est un groupe de méthodes (éventuellement incluant un type_argument_list), et A est un argument_listfacultatif, se compose des étapes suivantes :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:

  • L’ensemble des méthodes candidates pour l’appel de méthode est construit.The set of candidate methods for the method invocation is constructed. Pour chaque méthode F associé au groupe de méthodes M :For each method F associated with the method group M:
    • Si F n’est pas générique, F est candidat lorsque :If F is non-generic, F is a candidate when:
    • Si F est générique et que M n’a pas de liste d’arguments de type, F est candidat lorsque :If F is generic and M has no type argument list, F is a candidate when:
      • L’inférence de type (inférence de type) est réussie, en déduisant une liste d’arguments de type pour l’appel, etType inference (Type inference) succeeds, inferring a list of type arguments for the call, and
      • Une fois que les arguments de type inférés sont substitués aux paramètres de type de méthode correspondants, tous les types construits dans la liste de paramètres de F répondent à leurs contraintes (quisatisfont les contraintes) et la liste de paramètres de F est applicable avec en ce qui concerne A (fonction membre applicable).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).
    • Si F est générique et que M comprend une liste d’arguments de type, F est candidate dans les cas suivants :If F is generic and M includes a type argument list, F is a candidate when:
      • F a le même nombre de paramètres de type de méthode que ceux fournis dans la liste d’arguments de type, etF has the same number of method type parameters as were supplied in the type argument list, and
      • Une fois que les arguments de type sont substitués aux paramètres de type de méthode correspondants, tous les types construits dans la liste de paramètres de F répondent à leurs contraintes (quisatisfont les contraintes), et la liste de paramètres de F est applicable en ce qui concerne A (fonction membre applicable).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).
  • L’ensemble des méthodes candidates est réduit pour contenir uniquement des méthodes des types les plus dérivés : Pour chaque méthode C.F dans l’ensemble, où C est le type dans lequel la méthode F est déclarée, toutes les méthodes déclarées dans un type de base de C sont supprimées de l’ensemble.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. En outre, si C est un type de classe autre que object, toutes les méthodes déclarées dans un type interface sont supprimées de l’ensemble.Furthermore, if C is a class type other than object, all methods declared in an interface type are removed from the set. (Cette dernière règle a un impact uniquement lorsque le groupe de méthodes était le résultat d’une recherche de membre sur un paramètre de type ayant une classe de base effective autre que Object et un ensemble d’interfaces effectif non vide.)(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.)
  • Si le jeu résultant de méthodes candidates est vide, le traitement suivant des étapes suivantes est abandonné, et une tentative est effectuée pour traiter l’appel comme un appel de méthode d’extension (appels de méthode d’extension).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). En cas d’échec, il n’existe aucune méthode applicable et une erreur de liaison s’est produite.If this fails, then no applicable methods exist, and a binding-time error occurs.
  • La meilleure méthode de l’ensemble de méthodes candidates est identifiée à l’aide des règles de résolution de surcharge de la résolution de surcharge.The best method of the set of candidate methods is identified using the overload resolution rules of Overload resolution. Si une seule meilleure méthode ne peut pas être identifiée, l’appel de la méthode est ambigu et une erreur de liaison s’est produite.If a single best method cannot be identified, the method invocation is ambiguous, and a binding-time error occurs. Lors de l’exécution de la résolution de surcharge, les paramètres d’une méthode générique sont pris en compte après avoir remplacé les arguments de type (fournis ou déduits) pour les paramètres de type de méthode correspondants.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.
  • La validation finale de la meilleure méthode choisie est effectuée :Final validation of the chosen best method is performed:
    • La méthode est validée dans le contexte du groupe de méthodes : Si la meilleure méthode est une méthode statique, le groupe de méthodes doit avoir été généré à partir d’un simple_name ou d’un member_access par le biais d’un type.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. Si la meilleure méthode est une méthode d’instance, le groupe de méthodes doit avoir été généré à partir d’un simple_name, d’un member_access par le biais d’une variable ou d’une valeur ou d’un base_access.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. Si aucune de ces conditions n’est remplie, une erreur de liaison au moment de la liaison se produit.If neither of these requirements is true, a binding-time error occurs.
    • Si la meilleure méthode est une méthode générique, les arguments de type (fournis ou déduits) sont vérifiés par rapport aux contraintes (contraintes satisfaisantes) déclarées dans la méthode générique.If 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. Si un argument de type ne satisfait pas la ou les contraintes correspondantes sur le paramètre de type, une erreur de liaison s’est produite.If any type argument does not satisfy the corresponding constraint(s) on the type parameter, a binding-time error occurs.

Une fois qu’une méthode a été sélectionnée et validée au moment de la liaison par les étapes ci-dessus, l’appel réel au moment de l’exécution est traité en fonction des règles d’appel des membres de fonction décrites dans vérification de la résolution de surcharge dynamiquepar la compilation.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.

L’effet intuitif des règles de résolution décrites ci-dessus est le suivant : Pour localiser la méthode particulière appelée par un appel de méthode, commencez par le type indiqué par l’appel de méthode et poursuivez la chaîne d’héritage jusqu’à ce qu’au moins une déclaration de méthode applicable, accessible et non substituée soit trouvée.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. Effectuez ensuite l’inférence de type et la résolution de surcharge sur l’ensemble des méthodes applicables, accessibles et non substituées déclarées dans ce type et appelez la méthode sélectionnée.Then 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. Si aucune méthode n’a été trouvée, essayez plutôt de traiter l’appel comme un appel de méthode d’extension.If no method was found, try instead to process the invocation as an extension method invocation.

Appels de méthode d’extensionExtension method invocations

Dans un appel de méthode (appels sur des instances boxed) de l’un des formulairesIn a method invocation (Invocations on boxed instances) of one of the forms

expr . identifier ( )

expr . identifier ( args )

expr . identifier < typeargs > ( )

expr . identifier < typeargs > ( args )

Si le traitement normal de l’appel ne trouve aucune méthode applicable, une tentative est faite pour traiter la construction comme un appel de méthode d’extension.if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. Si expr ou l’un des arguments a le type au moment de la compilation dynamic, les méthodes d’extension ne s’appliquent pas.If expr or any of the args has compile-time type dynamic, extension methods will not apply.

L’objectif est de trouver le meilleur type_name C, afin que l’appel de la méthode statique correspondante puisse avoir lieu :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 )

Une méthode d’extension Ci.Mj est éligible dans les cas suivants :An extension method Ci.Mj is eligible if:

  • Ci est une classe non générique et non imbriquéeCi is a non-generic, non-nested class
  • Le nom de Mj est identifierThe name of Mj is identifier
  • Mj est accessible et applicable lorsqu’il est appliqué aux arguments comme une méthode statique, comme indiqué ci-dessusMj is accessible and applicable when applied to the arguments as a static method as shown above
  • Une identité, une référence ou une conversion boxing implicite existe entre expr et le type du premier paramètre de Mj.An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter of Mj.

La recherche de C se déroule comme suit :The search for C proceeds as follows:

  • À partir de la déclaration d’espace de noms englobante la plus proche, en continuant avec chaque déclaration d’espace de noms englobant, et se terminant par l’unité de compilation conteneur, des tentatives successives sont effectuées pour trouver un ensemble candidat de méthodes d’extension :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:
    • Si l’espace de noms ou l’unité de compilation donné contient directement des déclarations de type non génériques Ci avec les méthodes d’extension éligibles Mj, le jeu de ces méthodes d’extension est l’ensemble de candidats.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.
    • Si les types Ci importés par using_static_declarations et déclarés directement dans les espaces de noms importés par using_namespace_directives dans l’espace de noms ou l’unité de compilation indiqué contiennent directement les méthodes d’extension éligibles Mj, l’ensemble de ces méthodes d’extension est l’ensemble de candidats.If types Ci imported by using_static_declarations and directly declared in namespaces imported by using_namespace_directives in the given namespace or compilation unit directly contain eligible extension methods Mj, then the set of those extension methods is the candidate set.
  • Si aucun jeu de candidats n’est trouvé dans une déclaration d’espace de noms ou une unité de compilation englobante, une erreur de compilation se produit.If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
  • Sinon, la résolution de surcharge est appliquée à l’ensemble de candidats comme décrit dans (résolution de surcharge).Otherwise, overload resolution is applied to the candidate set as described in (Overload resolution). Si aucune meilleure méthode n’est trouvée, une erreur de compilation se produit.If no single best method is found, a compile-time error occurs.
  • C est le type dans lequel la meilleure méthode est déclarée en tant que méthode d’extension.C is the type within which the best method is declared as an extension method.

À l’aide de C comme cible, l’appel de méthode est ensuite traité comme un appel de méthode statique (vérification au moment de la compilation de la résolution de surcharge dynamique).Using C as a target, the method call is then processed as a static method invocation (Compile-time checking of dynamic overload resolution).

Les règles précédentes signifient que les méthodes d’instance sont prioritaires sur les méthodes d’extension, que les méthodes d’extension disponibles dans les déclarations d’espace de noms interne ont la priorité sur les méthodes d’extension disponibles dans les déclarations d’espaces de noms externes, et cette extension les méthodes déclarées directement dans un espace de noms ont priorité sur les méthodes d’extension importées dans ce même espace de noms avec une directive d’espace de noms using.The 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. Exemple :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)
    }
}

Dans l’exemple, la méthode de B est prioritaire sur la première méthode d’extension, et la méthode de C est prioritaire sur les deux méthodes d’extension.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();
        }
    }
}

La sortie de cet exemple est la suivante :The output of this example is:

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

D.G est prioritaire sur C.G, et E.F est prioritaire sur D.F et C.F.D.G takes precedence over C.G, and E.F takes precedence over both D.F and C.F.

Appels déléguésDelegate invocations

Pour un appel de délégué, le primary_expression du invocation_expression doit être une valeur d’un delegate_type.For a delegate invocation, the primary_expression of the invocation_expression must be a value of a delegate_type. En outre, si l’on considère que le delegate_type est une fonction membre avec la même liste de paramètres que le delegate_type, delegate_type doit être applicable (fonction membre applicable) en ce qui concerne le argument_ liste des invocation_expression.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.

Le traitement au moment de l’exécution d’un appel de délégué de la forme D(A), où D est un primary_expression d’un delegate_type et A est un argument_listfacultatif, se compose des étapes suivantes :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 est évalué.D is evaluated. Si cette évaluation provoque une exception, aucune autre étape n’est exécutée.If this evaluation causes an exception, no further steps are executed.
  • La valeur de D est vérifiée comme valide.The value of D is checked to be valid. Si la valeur de D est null, une System.NullReferenceException est levée et aucune autre étape n’est exécutée.If the value of D is null, a System.NullReferenceException is thrown and no further steps are executed.
  • Dans le cas contraire, D est une référence à une instance de délégué.Otherwise, D is a reference to a delegate instance. Les appels de membre de fonction (vérification au moment de la compilation de la résolution de surcharge dynamique) sont exécutés sur chacune des entités pouvant être appelées dans la liste d’appel du délégué.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. Pour les entités pouvant être appelées constituées d’une méthode d’instance et d’instance, l’instance de l’appel est l’instance contenue dans l’entité pouvant être appelée.For callable entities consisting of an instance and instance method, the instance for the invocation is the instance contained in the callable entity.

Accès aux élémentsElement access

Un element_access se compose d’un primary_no_array_creation_expression, suivi d’un jeton « [ », suivi d’un argument_list, suivi d’un jeton « ] ».An element_access consists of a primary_no_array_creation_expression, followed by a "[" token, followed by an argument_list, followed by a "]" token. Le argument_list se compose d’un ou plusieurs arguments, séparés par des virgules.The argument_list consists of one or more arguments, separated by commas.

element_access
    : primary_no_array_creation_expression '[' expression_list ']'
    ;

Le argument_list d’un element_access n’est pas autorisé à contenir des arguments ref ou out.The argument_list of an element_access is not allowed to contain ref or out arguments.

Un element_access est lié dynamiquement (liaison dynamique) si au moins l’un des éléments suivants est présent :An element_access is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Le primary_no_array_creation_expression a un type au moment de la compilation dynamic.The primary_no_array_creation_expression has compile-time type dynamic.
  • Au moins une expression de argument_list a le type au moment de la compilation dynamic et le primary_no_array_creation_expression n’a pas de type tableau.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.

Dans ce cas, le compilateur classe element_access en tant que valeur de type dynamic.In this case the compiler classifies the element_access as a value of type dynamic. Les règles ci-dessous pour déterminer la signification des element_access sont ensuite appliquées au moment de l’exécution, à l’aide du type au moment de l’exécution et non du type au moment de la compilation de ceux des primary_no_array_creation_expression et argument_list les expressions qui ont le type au moment de la compilation 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. Si le primary_no_array_creation_expression n’a pas le type au moment de la compilation dynamic, l’accès à l’élément subit une vérification limitée au moment de la compilation, comme décrit dans contrôle de la résolution de surcharge dynamique au moment de la compilation.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.

Si le primary_no_array_creation_expression d’un element_access est une valeur d’un array_type, le element_access est un accès à un tableau (accès au tableau).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). Sinon, primary_no_array_creation_expression doit être une variable ou une valeur d’un type de classe, de struct ou d’interface qui possède un ou plusieurs membres de l’indexeur, auquel cas le element_access est un accès à un indexeur (accès à l’indexeur).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).

Accès aux tableauxArray access

Pour un accès à un tableau, le primary_no_array_creation_expression du element_access doit être une valeur d’un array_type.For an array access, the primary_no_array_creation_expression of the element_access must be a value of an array_type. En outre, le argument_list d’un accès à un tableau n’est pas autorisé à contenir des arguments nommés. Le nombre d’expressions dans argument_list doit être le même que le rang du array_type, et chaque expression doit être de type int, uint, long, ulong, ou doit être implicitement convertible en un ou plusieurs de ces types.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.

Le résultat de l’évaluation d’un accès à un tableau est une variable du type d’élément du tableau, à savoir l’élément de tableau sélectionné par la ou les valeurs de la ou des expressions dans le argument_list.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.

Le traitement au moment de l’exécution d’un accès à un tableau de la forme P[A], où P est un primary_no_array_creation_expression d’un array_type et A est un argument_list, se compose des étapes suivantes :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 est évalué.P is evaluated. Si cette évaluation provoque une exception, aucune autre étape n’est exécutée.If this evaluation causes an exception, no further steps are executed.
  • Les expressions d’index des argument_list sont évaluées dans l’ordre, de gauche à droite.The index expressions of the argument_list are evaluated in order, from left to right. Après l’évaluation de chaque expression d’index, une conversion implicite (conversions implicites) vers l’un des types suivants est effectuée : 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. Le premier type de cette liste pour lequel une conversion implicite existe est choisi.The first type in this list for which an implicit conversion exists is chosen. Par exemple, si l’expression d’index est de type short, une conversion implicite en int est effectuée, puisque les conversions implicites de short en int et de short à long sont possibles.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. Si l’évaluation d’une expression d’index ou de la conversion implicite suivante provoque une exception, aucune autre expression d’index n’est évaluée et aucune autre étape n’est exécutée.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.
  • La valeur de P est vérifiée comme valide.The value of P is checked to be valid. Si la valeur de P est null, une System.NullReferenceException est levée et aucune autre étape n’est exécutée.If the value of P is null, a System.NullReferenceException is thrown and no further steps are executed.
  • La valeur de chaque expression dans le argument_list est vérifiée par rapport aux limites réelles de chaque dimension de l’instance de tableau référencée par 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. Si une ou plusieurs valeurs sont hors limites, une System.IndexOutOfRangeException est levée et aucune autre étape n’est exécutée.If one or more values are out of range, a System.IndexOutOfRangeException is thrown and no further steps are executed.
  • L’emplacement de l’élément de tableau donné par la ou les expressions d’index est calculé et cet emplacement devient le résultat de l’accès au tableau.The location of the array element given by the index expression(s) is computed, and this location becomes the result of the array access.

Accès aux indexeursIndexer access

Pour un accès à un indexeur, le primary_no_array_creation_expression du element_access doit être une variable ou une valeur d’un type de classe, de struct ou d’interface, et ce type doit implémenter un ou plusieurs indexeurs applicables en ce qui concerne argument_list du element_access.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.

Le traitement au moment de la liaison d’un accès à un indexeur de la forme P[A], où P est un primary_no_array_creation_expression d’un type de classe, de struct ou d’interface T, et A est un argument_list, se compose des éléments suivants : étapesThe 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:

  • L’ensemble d’indexeurs fourni par T est construit.The set of indexers provided by T is constructed. L’ensemble se compose de tous les indexeurs déclarés dans T ou d’un type de base de T qui ne sont pas des déclarations override et qui sont accessibles dans le contexte actuel (accès aux membres).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).
  • Le jeu est réduit aux indexeurs applicables et non masqués par d’autres indexeurs.The set is reduced to those indexers that are applicable and not hidden by other indexers. Les règles suivantes sont appliquées à chaque indexeur S.I dans l’ensemble, où S est le type dans lequel l’indexeur I est déclaré :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:
    • Si I n’est pas applicable en ce qui concerne A (fonction membre applicable), I est supprimé du jeu.If I is not applicable with respect to A (Applicable function member), then I is removed from the set.
    • Si I est applicable en ce qui concerne A (fonction membre applicable), tous les indexeurs déclarés dans un type de base de S sont supprimés du jeu.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.
    • Si I est applicable en ce qui concerne A (fonction membre applicable) et S est un type de classe autre que object, tous les indexeurs déclarés dans une interface sont supprimés du jeu.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.
  • Si le jeu d’indexeurs candidats obtenu est vide, aucun indexeur applicable n’existe et une erreur de liaison est générée.If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
  • Le meilleur indexeur de l’ensemble des indexeurs candidats est identifié à l’aide des règles de résolution de surcharge de la résolution de surcharge.The best indexer of the set of candidate indexers is identified using the overload resolution rules of Overload resolution. Si un seul meilleur indexeur ne peut pas être identifié, l’accès à l’indexeur est ambigu et une erreur de liaison s’est produite.If a single best indexer cannot be identified, the indexer access is ambiguous, and a binding-time error occurs.
  • Les expressions d’index des argument_list sont évaluées dans l’ordre, de gauche à droite.The index expressions of the argument_list are evaluated in order, from left to right. Le résultat du traitement de l’accès à l’indexeur est une expression classée comme un accès à un indexeur.The result of processing the indexer access is an expression classified as an indexer access. L’expression d’accès de l’indexeur fait référence à l’indexeur déterminé à l’étape ci-dessus et a une expression d’instance associée de P et une liste d’arguments associée de 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.

En fonction du contexte dans lequel il est utilisé, un accès à l’indexeur entraîne l’appel de l' accesseur Get ou de l' accesseur Set de l’indexeur.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. Si l’accès à l’indexeur est la cible d’une assignation, l' accesseur Set est appelé pour assigner une nouvelle valeur (assignation simple).If the indexer access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). Dans tous les autres cas, l' accesseur Get est appelé pour obtenir la valeur actuelle (valeurs des expressions).In all other cases, the get accessor is invoked to obtain the current value (Values of expressions).

Cet accèsThis access

Un This_Access se compose du mot réservé this.A this_access consists of the reserved word this.

this_access
    : 'this'
    ;

Un This_Access est autorisé uniquement dans le bloc d’un constructeur d’instance, d’une méthode d’instance ou d’un accesseur d’instance.A this_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Il a l’une des significations suivantes :It has one of the following meanings:

  • Lorsque this est utilisé dans un primary_expression au sein d’un constructeur d’instance d’une classe, il est classé en tant que valeur.When this is used in a primary_expression within an instance constructor of a class, it is classified as a value. Le type de la valeur est le type d’instance (type d’instance) de la classe dans laquelle l’utilisation se produit, et la valeur est une référence à l’objet en cours de construction.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.
  • Lorsque this est utilisé dans un primary_expression dans une méthode d’instance ou un accesseur d’instance d’une classe, il est classé en tant que valeur.When this is used in a primary_expression within an instance method or instance accessor of a class, it is classified as a value. Le type de la valeur est le type d’instance (type d’instance) de la classe dans laquelle l’utilisation se produit, et la valeur est une référence à l’objet pour lequel la méthode ou l’accesseur a été appelé.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.
  • Lorsque this est utilisé dans un primary_expression au sein d’un constructeur d’instance d’un struct, il est classé en tant que variable.When this is used in a primary_expression within an instance constructor of a struct, it is classified as a variable. Le type de la variable est le type d’instance (type d’instance) de la structure dans laquelle l’utilisation se produit, et la variable représente le struct en cours de construction.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. La variable this d’un constructeur d’instance d’un struct se comporte exactement comme un paramètre out du type struct (en particulier, cela signifie que la variable doit être assignée de manière définitive dans chaque chemin d’exécution du constructeur d’instance).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.
  • Lorsque this est utilisé dans un primary_expression dans une méthode d’instance ou un accesseur d’instance d’un struct, il est classé en tant que variable.When this is used in a primary_expression within an instance method or instance accessor of a struct, it is classified as a variable. Le type de la variable est le type d’instance (type d’instance) de la structure dans laquelle l’utilisation se produit.The type of the variable is the instance type (The instance type) of the struct within which the usage occurs.
    • Si la méthode ou l’accesseur n’est pas un itérateur (itérateurs), la variable this représente le struct pour lequel la méthode ou l’accesseur a été appelé, et se comporte exactement comme un paramètre ref du type struct.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.
    • Si la méthode ou l’accesseur est un itérateur, la variable this représente une copie du struct pour lequel la méthode ou l’accesseur a été appelé, et se comporte exactement comme un paramètre de valeur du type struct.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.

L’utilisation de this dans un primary_expression dans un contexte autre que ceux listés ci-dessus est une erreur de compilation.Use of this in a primary_expression in a context other than the ones listed above is a compile-time error. En particulier, il n’est pas possible de faire référence à this dans une méthode statique, un accesseur de propriété statique ou dans un variable_initializer d’une déclaration de champ.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.

Accès de baseBase access

Un base_access se compose du mot réservé base suivi d’un jeton « . » et d’un identificateur ou d’un argument_list placé entre crochets :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 ']'
    ;

Un base_access est utilisé pour accéder aux membres de la classe de base qui sont masqués par des membres portant le même nom dans la classe ou le struct actuel.A base_access is used to access base class members that are hidden by similarly named members in the current class or struct. Un base_access est autorisé uniquement dans le bloc d’un constructeur d’instance, d’une méthode d’instance ou d’un accesseur d’instance.A base_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Lorsque base.I se produit dans une classe ou un struct, I doit désigner un membre de la classe de base de cette classe ou de ce struct.When base.I occurs in a class or struct, I must denote a member of the base class of that class or struct. De même, lorsque base[E] se produit dans une classe, un indexeur applicable doit exister dans la classe de base.Likewise, when base[E] occurs in a class, an applicable indexer must exist in the base class.

Au moment de la liaison, les expressions base_access de la forme base.I et base[E] sont évaluées exactement comme si elles étaient écrites ((B)this).I et ((B)this)[E], où B est la classe de base de la classe ou du struct dans lequel la construction se produit.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. Ainsi, base.I et base[E] correspondent à this.I et à this[E], sauf que this est affiché en tant qu’instance de la classe de base.Thus, base.I and base[E] correspond to this.I and this[E], except this is viewed as an instance of the base class.

Lorsqu’un base_access fait référence à un membre de fonction virtuelle (une méthode, une propriété ou un indexeur), la détermination du membre de fonction à appeler au moment de l’exécution (vérification de la résolution de surcharge dynamiqueau moment de la compilation) est modifiée.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. Le membre de fonction appelé est déterminé par la recherche de l’implémentation la plus dérivée (méthodes virtuelles) du membre de fonction en ce qui concerne B (plutôt que par rapport au type d’exécution de this, comme normalement dans un accès non-base) .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). Ainsi, dans un override d’un membre de fonction virtual, un base_access peut être utilisé pour appeler l’implémentation héritée du membre de fonction.Thus, within an override of a virtual function member, a base_access can be used to invoke the inherited implementation of the function member. Si le membre de fonction référencé par un base_access est abstrait, une erreur de liaison au moment de la liaison se produit.If the function member referenced by a base_access is abstract, a binding-time error occurs.

Opérateurs suffixés d’incrémentation et de décrémentationPostfix increment and decrement operators

post_increment_expression
    : primary_expression '++'
    ;

post_decrement_expression
    : primary_expression '--'
    ;

L’opérande d’une opération d’incrémentation ou de décrémentation suffixée doit être une expression classifiée comme une variable, un accès à une propriété ou un accès à un indexeur.The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Le résultat de l’opération est une valeur du même type que l’opérande.The result of the operation is a value of the same type as the operand.

Si le primary_expression a le type au moment de la compilation dynamic, l’opérateur est lié dynamiquement (liaison dynamique), post_increment_expression ou post_decrement_expression a le type au moment de la compilation dynamic et les règles suivantes sont appliquées au moment de l’exécution à l’aide du type d’exécution de primary_expression.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.

Si l’opérande d’une opération d’incrémentation ou de décrémentation suffixée est un accès à une propriété ou un indexeur, la propriété ou l’indexeur doit avoir à la fois un accesseur get et un accesseur set.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. Si ce n’est pas le cas, une erreur de temps de liaison se produit.If this is not the case, a binding-time error occurs.

La résolution de surcharge d’opérateur unaire (résolution de surcharge d’opérateur unaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Les opérateurs prédéfinis ++ et -- existent pour les types suivants : sbyte, byte, short, ushort, int, uint, long, ulong, 0, 1, 2, 3 et tout type enum.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Les opérateurs ++ prédéfinis retournent la valeur produite par l’ajout de 1 à l’opérande, et les opérateurs -- prédéfinis retournent la valeur produite par la soustraction de 1 de l’opérande.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. Dans un contexte checked, si le résultat de cet ajout ou de cette soustraction est en dehors de la plage du type de résultat et que le type de résultat est un type intégral ou un type enum, une System.OverflowException est levée.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.

Le traitement au moment de l’exécution d’une opération d’incrémentation ou de décrémentation suffixée au format x++ ou x-- se compose des étapes suivantes :The run-time processing of a postfix increment or decrement operation of the form x++ or x-- consists of the following steps:

  • Si x est classée en tant que variable :If x is classified as a variable:
    • x est évaluée pour produire la variable.x is evaluated to produce the variable.
    • La valeur de x est enregistrée.The value of x is saved.
    • L’opérateur sélectionné est appelé avec la valeur enregistrée de x comme argument.The selected operator is invoked with the saved value of x as its argument.
    • La valeur retournée par l’opérateur est stockée dans l’emplacement donné par l’évaluation de x.The value returned by the operator is stored in the location given by the evaluation of x.
    • La valeur enregistrée de x devient le résultat de l’opération.The saved value of x becomes the result of the operation.
  • Si x est classé comme un accès à une propriété ou un indexeur :If x is classified as a property or indexer access:
    • L’expression d’instance (si x n’est pas static) et la liste d’arguments (si x est un accès à un indexeur) associée à x sont évaluées, et les résultats sont utilisés dans les appels d’accesseur get et set suivants.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.
    • L’accesseur get de x est appelé et la valeur retournée est enregistrée.The get accessor of x is invoked and the returned value is saved.
    • L’opérateur sélectionné est appelé avec la valeur enregistrée de x comme argument.The selected operator is invoked with the saved value of x as its argument.
    • L’accesseur set de x est appelé avec la valeur retournée par l’opérateur comme argument value.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • La valeur enregistrée de x devient le résultat de l’opération.The saved value of x becomes the result of the operation.

Les opérateurs ++ et -- prennent également en charge la notation de préfixe (opérateurs de préfixe d’incrémentation et de décrémentation).The ++ and -- operators also support prefix notation (Prefix increment and decrement operators). En général, le résultat de x++ ou x-- est la valeur de x avant l’opération, alors que le résultat de ++x ou --x est la valeur de x après l’opération.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. Dans les deux cas, x lui-même a la même valeur après l’opération.In either case, x itself has the same value after the operation.

Une implémentation operator ++ ou operator -- peut être appelée à l’aide de la notation postfix ou préfixe.An operator ++ or operator -- implementation can be invoked using either postfix or prefix notation. Il n’est pas possible d’avoir des implémentations d’opérateur distinctes pour les deux notations.It is not possible to have separate operator implementations for the two notations.

new, opérateurThe new operator

L’opérateur new est utilisé pour créer de nouvelles instances de types.The new operator is used to create new instances of types.

Il existe trois formes d’expressions new :There are three forms of new expressions:

  • Les expressions de création d’objet sont utilisées pour créer des instances de types de classe et de valeur.Object creation expressions are used to create new instances of class types and value types.
  • Les expressions de création de tableau sont utilisées pour créer de nouvelles instances de types tableau.Array creation expressions are used to create new instances of array types.
  • Les expressions de création de délégué sont utilisées pour créer de nouvelles instances de types délégués.Delegate creation expressions are used to create new instances of delegate types.

L’opérateur new implique la création d’une instance d’un type, mais n’implique pas nécessairement l’allocation dynamique de la mémoire.The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. En particulier, les instances de types valeur ne requièrent aucune mémoire supplémentaire au-delà des variables dans lesquelles elles résident et aucune allocation dynamique ne se produit lorsque new est utilisé pour créer des instances de types valeur.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.

Expressions de création d’objetObject creation expressions

Un object_creation_expression est utilisé pour créer une nouvelle instance d’un class_type ou d’un Value_type.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
    ;

Le type d’un object_creation_expression doit être un class_type, un Value_type ou un type_parameter.The type of an object_creation_expression must be a class_type, a value_type or a type_parameter. Le type ne peut pas être un abstract class_type.The type cannot be an abstract class_type.

Le argument_list facultatif (listes d’arguments) est autorisé uniquement si le type est un class_type ou un struct_type.The optional argument_list (Argument lists) is permitted only if the type is a class_type or a struct_type.

Une expression de création d’objet peut omettre la liste d’arguments de constructeur et les parenthèses englobantes fournies, elle comprend un initialiseur d’objet ou un initialiseur de collection.An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. L’omission de la liste d’arguments du constructeur et des parenthèses englobantes équivaut à spécifier une liste d’arguments vide.Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.

Le traitement d’une expression de création d’objet qui inclut un initialiseur d’objet ou un initialiseur de collection consiste à traiter en premier le constructeur d’instance, puis à traiter les initialisations de membre ou d’élément spécifiées par l’initialiseur d’objet (Initialiseurs d’objets) ou initialiseur de collection (initialiseurs de collection).Processing 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).

Si l’un des arguments dans le argument_list facultatif a le type au moment de la compilation dynamic, le object_creation_expression est lié dynamiquement (liaison dynamique) et les règles suivantes sont appliquées au moment de l’exécution à l’aide du Runtime type de ces arguments des argument_list qui ont le type au moment de la compilation 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. Toutefois, la création d’objet subit une vérification limitée au moment de la compilation, comme décrit dans vérification de la résolution de surcharge dynamiquepar la compilation.However, the object creation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

Le traitement au moment de la liaison d’un object_creation_expression de la forme new T(A), où T est un class_type ou un Value_type et A est un argument_listfacultatif, se compose des étapes suivantes :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:

  • Si T est un Value_type et A n’est pas présent :If T is a value_type and A is not present:
    • Object_creation_expression est un appel de constructeur par défaut.The object_creation_expression is a default constructor invocation. Le résultat de l' object_creation_expression est une valeur de type T, à savoir la valeur par défaut de T, comme défini dans le type System. ValueType.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.
  • Sinon, si T est un type_parameter et A n’est pas présent :Otherwise, if T is a type_parameter and A is not present:
    • Si aucune contrainte de type valeur ou contrainte de constructeur (contraintes de paramètre de type) n’a été spécifiée pour T, une erreur de liaison s’est produite.If no value type constraint or constructor constraint (Type parameter constraints) has been specified for T, a binding-time error occurs.
    • Le résultat de l' object_creation_expression est une valeur du type au moment de l’exécution auquel le paramètre de type a été lié, à savoir le résultat de l’appel du constructeur par défaut de ce type.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. Le type au moment de l’exécution peut être un type référence ou un type valeur.The run-time type may be a reference type or a value type.
  • Sinon, si T est un class_type ou un struct_type:Otherwise, if T is a class_type or a struct_type:
    • Si T est un class_typeabstract, une erreur de compilation se produit.If T is an abstract class_type, a compile-time error occurs.
    • Le constructeur d’instance à appeler est déterminé à l’aide des règles de résolution de surcharge de la résolution de surcharge.The instance constructor to invoke is determined using the overload resolution rules of Overload resolution. L’ensemble de constructeurs d’instance candidat se compose de tous les constructeurs d’instance accessibles déclarés dans T, applicables en ce qui concerne A (fonction membre applicable).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). Si le jeu de constructeurs d’instance candidat est vide, ou si un seul constructeur d’instance unique ne peut pas être identifié, une erreur de liaison s’est produite.If the set of candidate instance constructors is empty, or if a single best instance constructor cannot be identified, a binding-time error occurs.
    • Le résultat de l' object_creation_expression est une valeur de type T, à savoir la valeur produite par l’appel du constructeur d’instance déterminé à l’étape ci-dessus.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.
  • Dans le cas contraire, le object_creation_expression n’est pas valide et une erreur de liaison s’est produite.Otherwise, the object_creation_expression is invalid, and a binding-time error occurs.

Même si le object_creation_expression est lié dynamiquement, le type au moment de la compilation est toujours T.Even if the object_creation_expression is dynamically bound, the compile-time type is still T.

Le traitement au moment de l’exécution d’un object_creation_expression de la forme new T(A), où T est class_type ou struct_type et A est un argument_listfacultatif, se compose des étapes suivantes :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:

  • Si T est un class_type:If T is a class_type:
    • Une nouvelle instance de la classe T est allouée.A new instance of class T is allocated. Si la mémoire disponible est insuffisante pour allouer la nouvelle instance, une System.OutOfMemoryException est levée et aucune autre étape n’est exécutée.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • Tous les champs de la nouvelle instance sont initialisés à leurs valeurs par défaut (valeurs par défaut).All fields of the new instance are initialized to their default values (Default values).
    • Le constructeur d’instance est appelé selon les règles d’appel de membre de fonction (vérification au moment de la compilation de la résolution de surcharge dynamique).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Une référence à l’instance qui vient d’être allouée est automatiquement passée au constructeur d’instance et l’instance est accessible à partir de ce constructeur en tant que 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.
  • Si T est un struct_type:If T is a struct_type:
    • Une instance de type T est créée en allouant une variable locale temporaire.An instance of type T is created by allocating a temporary local variable. Étant donné qu’un constructeur d’instance d’un struct_type est requis pour assigner une valeur à chaque champ de l’instance en cours de création, aucune initialisation de la variable temporaire n’est nécessaire.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.
    • Le constructeur d’instance est appelé selon les règles d’appel de membre de fonction (vérification au moment de la compilation de la résolution de surcharge dynamique).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Une référence à l’instance qui vient d’être allouée est automatiquement passée au constructeur d’instance et l’instance est accessible à partir de ce constructeur en tant que 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.

Initialiseurs d’objetObject initializers

Un initialiseur d’objet spécifie des valeurs pour zéro, un ou plusieurs champs, propriétés ou éléments indexés d’un objet.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
    ;

Un initialiseur d’objet se compose d’une séquence d’initialiseurs de membres, placée entre des jetons { et } et séparés par des virgules.An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas. Chaque member_initializer désigne une cible pour l’initialisation.Each member_initializer designates a target for the initialization. Un identificateur doit nommer un champ ou une propriété accessible de l’objet en cours d’initialisation, alors qu’un argument_list placé entre crochets doit spécifier des arguments pour un indexeur accessible sur l’objet en cours d’initialisation.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. Il y a une erreur pour qu’un initialiseur d’objet inclue plusieurs initialiseurs de membre pour le même champ ou la même propriété.It is an error for an object initializer to include more than one member initializer for the same field or property.

Chaque initializer_target est suivi d’un signe égal et d’une expression, d’un initialiseur d’objet ou d’un initialiseur de collection.Each initializer_target is followed by an equals sign and either an expression, an object initializer or a collection initializer. Les expressions dans l’initialiseur d’objet ne peuvent pas faire référence à l’objet nouvellement créé qu’il initialise.It is not possible for expressions within the object initializer to refer to the newly created object it is initializing.

Un initialiseur de membre qui spécifie une expression après que le signe égal est traité de la même façon qu’une assignation (assignation simple) à la cible.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.

Un initialiseur de membre qui spécifie un initialiseur d’objet après que le signe égal est un initialiseur d’objet imbriqué, c.-à-d. une initialisation d’un objet incorporé.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. Au lieu d’assigner une nouvelle valeur au champ ou à la propriété, les assignations dans l’initialiseur d’objet imbriqué sont traitées comme des assignations aux membres du champ ou de la propriété.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. Les initialiseurs d’objets imbriqués ne peuvent pas être appliqués à des propriétés avec un type valeur, ou à des champs en lecture seule avec un type valeur.Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.

Un initialiseur de membre qui spécifie un initialiseur de collection après le signe égal est l’initialisation d’une collection incorporée.A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Au lieu d’assigner une nouvelle collection au champ, à la propriété ou à l’indexeur cible, les éléments fournis dans l’initialiseur sont ajoutés à la collection référencée par la cible.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. La cible doit être d’un type de collection qui satisfait aux exigences spécifiées dans les initialiseurs de collection.The target must be of a collection type that satisfies the requirements specified in Collection initializers.

Les arguments d’un initialiseur d’index seront toujours évalués une seule fois.The arguments to an index initializer will always be evaluated exactly once. Ainsi, même si les arguments finissent par ne jamais être utilisés (par exemple, en raison d’un initialiseur imbriqué vide), ils sont évalués pour leurs effets secondaires.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.

La classe suivante représente un point avec deux coordonnées :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; } }
}

Une instance de Point peut être créée et initialisée comme suit :An instance of Point can be created and initialized as follows:

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

ce qui a le même effet quewhich has the same effect as

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

__a est une variable temporaire inaccessible et invisible.where __a is an otherwise invisible and inaccessible temporary variable. La classe suivante représente un rectangle créé à partir de deux points :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; } }
}

Une instance de Rectangle peut être créée et initialisée comme suit :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 }
};

ce qui a le même effet quewhich 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;

__r, __p1 et __p2 sont des variables temporaires qui, sinon, sont inaccessibles et inaccessibles.where __r, __p1 and __p2 are temporary variables that are otherwise invisible and inaccessible.

Si le constructeur de Rectangle alloue les deux instances Point incorporéesIf 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; } }
}

la construction suivante peut être utilisée pour initialiser les instances Point incorporées au lieu d’assigner de nouvelles instances :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 }
};

ce qui a le même effet quewhich 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;

Dans le cas d’une définition appropriée de C, l’exemple suivant :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] = {}
};

équivaut à cette série d’affectations :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;

où les __c, etc., sont des variables générées qui sont invisibles et inaccessibles au code source.where __c, etc., are generated variables that are invisible and inaccessible to the source code. Notez que les arguments de [0,0] sont évalués une seule fois, et les arguments de [1,2] sont évalués une seule fois, même s’ils ne sont jamais utilisés.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.

Initialiseurs de collectionCollection initializers

Un initialiseur de collection spécifie les éléments d’une collection.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)*
    ;

Un initialiseur de collection se compose d’une séquence d’initialiseurs d’éléments, encadrés par des jetons { et } et séparés par des virgules.A collection initializer consists of a sequence of element initializers, enclosed by { and } tokens and separated by commas. Chaque initialiseur d’élément spécifie un élément à ajouter à l’objet de collection qui est initialisé, et se compose d’une liste d’expressions encadrées par des jetons { et } et séparés par des virgules.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. Un initialiseur d’élément à une seule expression peut être écrit sans accolades, mais il ne peut pas être une expression d’assignation, afin d’éviter toute ambiguïté avec les initialiseurs de membres.A single-expression element initializer can be written without braces, but cannot then be an assignment expression, to avoid ambiguity with member initializers. La production non_assignment_expression est définie dans expression.The non_assignment_expression production is defined in Expression.

L’exemple suivant illustre une expression de création d’objet qui comprend un initialiseur de collection :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 };

L’objet de collection auquel un initialiseur de collection est appliqué doit être d’un type qui implémente System.Collections.IEnumerable ou une erreur de compilation se produit.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. Pour chaque élément spécifié dans l’ordre, l’initialiseur de collection appelle une méthode Add sur l’objet cible avec la liste d’expressions de l’initialiseur d’élément comme liste d’arguments, en appliquant une recherche de membre normale et une résolution de surcharge pour chaque appel.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. Ainsi, l’objet de collection doit avoir une instance ou une méthode d’extension applicable portant le nom Add pour chaque initialiseur d’élément.Thus, the collection object must have an applicable instance or extension method with the name Add for each element initializer.

La classe suivante représente un contact avec un nom et une liste de numéros de téléphone :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; } }
}

Une List<Contact> peut être créée et initialisée comme suit :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" }
    }
};

ce qui a le même effet quewhich 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;

__clist, __c1 et __c2 sont des variables temporaires qui, sinon, sont inaccessibles et inaccessibles.where __clist, __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.

Expressions de création de tableauArray creation expressions

Un array_creation_expression est utilisé pour créer une nouvelle instance d’un array_type.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
    ;

Une expression de création de tableau de la première forme alloue une instance de tableau du type qui résulte de la suppression de chacune des expressions individuelles de la liste d’expressions.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. Par exemple, l’expression de création de tableau new int[10,20] produit une instance de tableau de type int[,], et l’expression de création de tableau new int[10][,] produit un tableau de type 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[][,]. Chaque expression de la liste d’expressions doit être de type int, uint, long ou ulong, ou implicitement convertible en un ou plusieurs de ces types.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. La valeur de chaque expression détermine la longueur de la dimension correspondante dans l’instance de tableau qui vient d’être allouée.The value of each expression determines the length of the corresponding dimension in the newly allocated array instance. Dans la mesure où la longueur d’une dimension de tableau ne doit pas être négative, il s’agit d’une erreur de compilation d’un constant_expression avec une valeur négative dans la liste d’expressions.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.

Sauf dans un contexte non sécurisé (contextes non sécurisés), la disposition des tableaux n’est pas spécifiée.Except in an unsafe context (Unsafe contexts), the layout of arrays is unspecified.

Si une expression de création de tableau du premier formulaire comprend un initialiseur de tableau, chaque expression de la liste d’expressions doit être une constante et le rang et les longueurs de dimensions spécifiés par la liste d’expressions doivent correspondre à ceux de l’initialiseur de tableau.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.

Dans une expression de création de tableau de la deuxième ou de la troisième forme, le rang du type de tableau ou du spécificateur de rangs spécifié doit correspondre à celui de l’initialiseur de tableau.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. Les longueurs de dimensions individuelles sont déduites du nombre d’éléments dans chacun des niveaux d’imbrication correspondants de l’initialiseur de tableau.The individual dimension lengths are inferred from the number of elements in each of the corresponding nesting levels of the array initializer. Ainsi, l’expressionThus, the expression

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

correspond exactement àexactly corresponds to

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

Une expression de création de tableau de la troisième forme est appelée expression de création de tableau implicitement typée.An array creation expression of the third form is referred to as an implicitly typed array creation expression. Elle est similaire à la deuxième forme, à ceci près que le type d’élément du tableau n’est pas explicitement donné, mais déterminé comme le meilleur type commun (recherche du meilleur type commun d’un ensemble d’expressions) du jeu d’expressions dans l’initialiseur de tableau.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. Dans le cas d’un tableau multidimensionnel, c’est-à-dire un où le rank_specifier contient au moins une virgule, cet ensemble comprend toutes les expressionsqui se trouvent dans les array_initializerimbriqué s.For a multidimensional array, i.e., one where the rank_specifier contains at least one comma, this set comprises all expressions found in nested array_initializers.

Les initialiseurs de tableau sont décrits plus en détail dans les initialiseurs de tableau.Array initializers are described further in Array initializers.

Le résultat de l’évaluation d’une expression de création de tableau est classé comme une valeur, à savoir une référence à l’instance de tableau nouvellement allouée.The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. Le traitement au moment de l’exécution d’une expression de création de tableau se compose des étapes suivantes :The run-time processing of an array creation expression consists of the following steps:

  • Les expressions de longueur de dimension des expression_list sont évaluées dans l’ordre, de gauche à droite.The dimension length expressions of the expression_list are evaluated in order, from left to right. Après l’évaluation de chaque expression, une conversion implicite (conversions implicites) vers l’un des types suivants est effectuée : 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. Le premier type de cette liste pour lequel une conversion implicite existe est choisi.The first type in this list for which an implicit conversion exists is chosen. Si l’évaluation d’une expression ou de la conversion implicite suivante provoque une exception, aucune autre expression n’est évaluée et aucune autre étape n’est exécutée.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.
  • Les valeurs calculées pour les longueurs de dimensions sont validées comme suit.The computed values for the dimension lengths are validated as follows. Si une ou plusieurs valeurs sont inférieures à zéro, une System.OverflowException est levée et aucune autre étape n’est exécutée.If one or more of the values are less than zero, a System.OverflowException is thrown and no further steps are executed.
  • Une instance de tableau avec les longueurs de dimensions données est allouée.An array instance with the given dimension lengths is allocated. Si la mémoire disponible est insuffisante pour allouer la nouvelle instance, une System.OutOfMemoryException est levée et aucune autre étape n’est exécutée.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
  • Tous les éléments de la nouvelle instance de tableau sont initialisés à leurs valeurs par défaut (valeurs par défaut).All elements of the new array instance are initialized to their default values (Default values).
  • Si l’expression de création de tableau contient un initialiseur de tableau, chaque expression de l’initialiseur de tableau est évaluée et assignée à son élément de tableau correspondant.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. Les évaluations et les assignations sont effectuées dans l’ordre dans lequel les expressions sont écrites dans l’initialiseur de tableau. en d’autres termes, les éléments sont initialisés dans l’ordre d’index de croissance, avec la dimension la plus à droite qui s’incrémente en premier.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. Si l’évaluation d’une expression donnée ou de l’assignation suivante à l’élément de tableau correspondant provoque une exception, aucun autre élément n’est initialisé (et les éléments restants auront donc leurs valeurs par défaut).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).

Une expression de création de tableau autorise l’instanciation d’un tableau avec des éléments d’un type tableau, mais les éléments d’un tel tableau doivent être initialisés manuellement.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. Par exemple, l’instructionFor example, the statement

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

crée un tableau unidimensionnel avec 100 éléments de type int[].creates a single-dimensional array with 100 elements of type int[]. La valeur initiale de chaque élément est null.The initial value of each element is null. Il n’est pas possible pour la même expression de création de tableau d’instancier également les sous-tableaux, et l’instructionIt 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

génère une erreur au moment de la compilation.results in a compile-time error. L’instanciation des sous-tableaux doit plutôt être effectuée manuellement, comme dansInstantiation 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];

Lorsqu’un tableau de tableaux a une forme « rectangulaire », c’est-à-dire lorsque les sous-tableaux sont tous de la même longueur, il est plus efficace d’utiliser un tableau multidimensionnel.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. Dans l’exemple ci-dessus, l’instanciation du tableau de tableaux crée 101 objets, un tableau externe et des sous-tableaux 100.In the example above, instantiation of the array of arrays creates 101 objects—one outer array and 100 sub-arrays. En revanche,In contrast,

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

crée un seul objet, un tableau à deux dimensions, et accomplit l’allocation dans une instruction unique.creates only a single object, a two-dimensional array, and accomplishes the allocation in a single statement.

Voici des exemples d’expressions de création de tableau implicitement typées :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

La dernière expression provoque une erreur au moment de la compilation, car ni int, ni string n’est implicitement convertible en l’autre, et il n’y a donc pas de type commun optimal.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. Une expression de création de tableau explicitement typée doit être utilisée dans ce cas, par exemple, en spécifiant que le type doit être object[].An explicitly typed array creation expression must be used in this case, for example specifying the type to be object[]. L’un des éléments peut également être casté en un type de base commun, qui devient alors le type d’élément inféré.Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.

Les expressions de création de tableau implicitement typées peuvent être combinées avec des initialiseurs d’objets anonymes (expressions de création d’objets anonymes) pour créer des structures de données typées anonymement.Implicitly typed array creation expressions can be combined with anonymous object initializers (Anonymous object creation expressions) to create anonymously typed data structures. Exemple :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" }
    }
};

Expressions de création de déléguéDelegate creation expressions

Un delegate_creation_expression est utilisé pour créer une nouvelle instance d’un delegate_type.A delegate_creation_expression is used to create a new instance of a delegate_type.

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

L’argument d’une expression de création de délégué doit être un groupe de méthodes, une fonction anonyme ou une valeur du type au moment de la compilation dynamic ou delegate_type.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. Si l’argument est un groupe de méthodes, il identifie la méthode et, pour une méthode d’instance, l’objet pour lequel créer un délégué.If the argument is a method group, it identifies the method and, for an instance method, the object for which to create a delegate. Si l’argument est une fonction anonyme, il définit directement les paramètres et le corps de la méthode de la cible du délégué.If the argument is an anonymous function it directly defines the parameters and method body of the delegate target. Si l’argument est une valeur, il identifie une instance de délégué de laquelle créer une copie.If the argument is a value it identifies a delegate instance of which to create a copy.

Si l' expression a le type au moment de la compilation dynamic, delegate_creation_expression est lié dynamiquement (liaison dynamique) et les règles ci-dessous sont appliquées au moment de l’exécution en utilisant le type d’exécution de l' expression.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. Dans le cas contraire, les règles sont appliquées au moment de la compilation.Otherwise the rules are applied at compile-time.

Le traitement au moment de la liaison d’un delegate_creation_expression de la forme new D(E), où D est un delegate_type et E est une expression, se compose des étapes suivantes :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:

  • Si E est un groupe de méthodes, l’expression de création de délégué est traitée de la même façon qu’une conversion de groupe de méthodes (conversions de groupe de méthodes) de E à 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.
  • Si E est une fonction anonyme, l’expression de création de délégué est traitée de la même façon qu’une conversion de fonction anonyme (conversions de fonctions anonymes) de E en 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.
  • Si E est une valeur, E doit être compatible (déclarations déléguées) avec D, et le résultat est une référence à un délégué nouvellement créé de type D qui fait référence à la même liste d’appel que 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. Si E n’est pas compatible avec D, une erreur de compilation se produit.If E is not compatible with D, a compile-time error occurs.

Le traitement au moment de l’exécution d’un delegate_creation_expression de la forme new D(E), où D est un delegate_type et E est une expression, se compose des étapes suivantes :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:

  • Si E est un groupe de méthodes, l’expression de création de délégué est évaluée comme une conversion de groupe de méthodes (conversions de groupe de méthodes) de E en 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.
  • Si E est une fonction anonyme, la création du délégué est évaluée comme une conversion de fonction anonyme de E en D (conversions de fonctions anonymes).If E is an anonymous function, the delegate creation is evaluated as an anonymous function conversion from E to D (Anonymous function conversions).
  • Si E est la valeur d’un delegate_type:If E is a value of a delegate_type:
    • E est évalué.E is evaluated. Si cette évaluation provoque une exception, aucune autre étape n’est exécutée.If this evaluation causes an exception, no further steps are executed.
    • Si la valeur de E est null, une System.NullReferenceException est levée et aucune autre étape n’est exécutée.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Une nouvelle instance du type délégué D est allouée.A new instance of the delegate type D is allocated. Si la mémoire disponible est insuffisante pour allouer la nouvelle instance, une System.OutOfMemoryException est levée et aucune autre étape n’est exécutée.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • La nouvelle instance de délégué est initialisée avec la même liste d’appel que l’instance de délégué donnée par E.The new delegate instance is initialized with the same invocation list as the delegate instance given by E.

La liste d’appel d’un délégué est déterminée lorsque le délégué est instancié, puis reste constante pendant toute la durée de vie du délégué.The invocation list of a delegate is determined when the delegate is instantiated and then remains constant for the entire lifetime of the delegate. En d’autres termes, il n’est pas possible de modifier les entités pouvant être appelées par Target d’un délégué une fois qu’il a été créé.In other words, it is not possible to change the target callable entities of a delegate once it has been created. Quand deux délégués sont combinés ou s’ils sont supprimés d’un autre (déclarations déléguées), un nouveau délégué est obtenu ; aucun contenu n’a été modifié pour le délégué existant.When two delegates are combined or one is removed from another (Delegate declarations), a new delegate results; no existing delegate has its contents changed.

Il n’est pas possible de créer un délégué qui fait référence à une propriété, un indexeur, un opérateur défini par l’utilisateur, un constructeur d’instance, un destructeur ou un constructeur statique.It is not possible to create a delegate that refers to a property, indexer, user-defined operator, instance constructor, destructor, or static constructor.

Comme décrit ci-dessus, quand un délégué est créé à partir d’un groupe de méthodes, la liste de paramètres formels et le type de retour du délégué déterminent les méthodes surchargées à sélectionner.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. Dans l’exempleIn 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;
    }
}

le champ A.f est initialisé avec un délégué qui fait référence à la deuxième méthode Square car cette méthode correspond exactement à la liste de paramètres formels et au type de retour de 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. Si la deuxième méthode Square n’était pas présente, une erreur de compilation s’est produite.Had the second Square method not been present, a compile-time error would have occurred.

Expressions de création d’objets anonymesAnonymous object creation expressions

Un anonymous_object_creation_expression est utilisé pour créer un objet d’un type anonyme.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
    ;

Un initialiseur d’objet anonyme déclare un type anonyme et retourne une instance de ce type.An anonymous object initializer declares an anonymous type and returns an instance of that type. Un type anonyme est un type de classe sans valeur qui hérite directement de object.An anonymous type is a nameless class type that inherits directly from object. Les membres d’un type anonyme sont une séquence de propriétés en lecture seule déduites de l’initialiseur d’objet anonyme utilisé pour créer une instance du type.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. Plus précisément, un initialiseur d’objet anonyme de la formeSpecifically, an anonymous object initializer of the form

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

déclare un type anonyme de la formedeclares 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() { ... }
}

où chaque Tx est le type de l’expression correspondante ex.where each Tx is the type of the corresponding expression ex. L’expression utilisée dans un member_declarator doit avoir un type.The expression used in a member_declarator must have a type. Par conséquent, il s’agit d’une erreur de compilation pour qu’une expression d’un member_declarator soit null ou une fonction anonyme.Thus, it is a compile-time error for an expression in a member_declarator to be null or an anonymous function. Il s’agit également d’une erreur au moment de la compilation pour que l’expression ait un type non sécurisé.It is also a compile-time error for the expression to have an unsafe type.

Les noms d’un type anonyme et du paramètre de sa méthode Equals sont générés automatiquement par le compilateur et ne peuvent pas être référencés dans le texte du programme.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.

Dans le même programme, deux initialiseurs d’objets anonymes qui spécifient une séquence de propriétés des mêmes noms et types au moment de la compilation dans le même ordre produisent des instances du même type anonyme.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.

Dans l’exempleIn the example

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

l’assignation sur la dernière ligne est autorisée, car p1 et p2 sont du même type anonyme.the assignment on the last line is permitted because p1 and p2 are of the same anonymous type.

Les méthodes Equals et GetHashcode sur les types anonymes substituent les méthodes héritées de object, et sont définies en termes de Equals et GetHashcode des propriétés, afin que deux instances du même type anonyme soient égales si et seulement si toutes leurs propriétés sont valeur.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.

Un déclarateur de membre peut être abrégé en un nom simple (inférence de type), un accès aux membres (vérification au moment de la compilation de la résolution de surcharge dynamique), un accès de base (accès de base) ou un accès de membre conditionnel null ( Expressions conditionnelles null en tant qu’initialiseurs de projection).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). C’est ce qu’on appelle un initialiseur de projection et est un raccourci pour une déclaration et une assignation à une propriété du même nom.This is called a projection initializer and is shorthand for a declaration of and assignment to a property with the same name. Plus précisément, les déclarateurs de membres des formulairesSpecifically, member declarators of the forms

identifier
expr.identifier

sont exactement équivalents à ce qui suit, respectivement :are precisely equivalent to the following, respectively:

identifier = identifier
identifier = expr.identifier

Ainsi, dans un initialiseur de projection, l' identificateur sélectionne à la fois la valeur et le champ ou la propriété auquel la valeur est assignée.Thus, in a projection initializer the identifier selects both the value and the field or property to which the value is assigned. Intuitivement, un initialiseur de projection projette non seulement une valeur, mais également le nom de la valeur.Intuitively, a projection initializer projects not just a value, but also the name of the value.

Opérateur typeofThe typeof operator

L’opérateur typeof est utilisé pour obtenir l’objet System.Type pour un type.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
    : ','
    ;

La première forme de typeof_expression se compose d’un mot clé typeof suivi d’un typeentre parenthèses.The first form of typeof_expression consists of a typeof keyword followed by a parenthesized type. Le résultat d’une expression de ce formulaire est l’objet System.Type pour le type indiqué.The result of an expression of this form is the System.Type object for the indicated type. Il n’existe qu’un seul objet System.Type pour un type donné.There is only one System.Type object for any given type. Cela signifie que pour un type @ no__t-0, typeof(T) == typeof(T) a toujours la valeur true.This means that for a type T, typeof(T) == typeof(T) is always true. Le type ne peut pas être dynamic.The type cannot be dynamic.

La deuxième forme de typeof_expression se compose d’un mot clé typeof suivi d’un unbound_type_nameentre parenthèses.The second form of typeof_expression consists of a typeof keyword followed by a parenthesized unbound_type_name. Un unbound_type_name est très similaire à un type_name (espace de noms et nom de type), sauf qu’un unbound_type_name contient generic_dimension_specifiers où un type_name contient TYPE_ argument_lists.An unbound_type_name is very similar to a type_name (Namespace and type names) except that an unbound_type_name contains generic_dimension_specifiers where a type_name contains type_argument_lists. Lorsque l’opérande d’un typeof_expression est une séquence de jetons qui satisfait les grammaires de unbound_type_name et type_name, à savoir lorsqu’il ne contient ni generic_dimension_specifier ni type_argument _list, la séquence de jetons est considérée comme un type_name.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. La signification d’un unbound_type_name est déterminée comme suit :The meaning of an unbound_type_name is determined as follows:

  • Convertissez la séquence de jetons en type_name en remplaçant chaque generic_dimension_specifier par un type_argument_list qui a le même nombre de virgules et le mot clé object comme chaque type_argument.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.
  • Évaluez le type_namerésultant, tout en ignorant toutes les contraintes de paramètre de type.Evaluate the resulting type_name, while ignoring all type parameter constraints.
  • Le unbound_type_name est résolu en type générique indépendant associé au type construit résultant (types liés et indépendants).The unbound_type_name resolves to the unbound generic type associated with the resulting constructed type (Bound and unbound types).

Le résultat de l' typeof_expression est l’objet System.Type pour le type générique indépendant qui en résulte.The result of the typeof_expression is the System.Type object for the resulting unbound generic type.

La troisième forme de typeof_expression se compose d’un mot clé typeof suivi d’un mot clé void entre parenthèses.The third form of typeof_expression consists of a typeof keyword followed by a parenthesized void keyword. Le résultat d’une expression de ce formulaire est l’objet System.Type qui représente l’absence d’un type.The result of an expression of this form is the System.Type object that represents the absence of a type. L’objet de type retourné par typeof(void) est différent de l’objet de type retourné pour tout type.The type object returned by typeof(void) is distinct from the type object returned for any type. Cet objet de type spécial est utile dans les bibliothèques de classes qui autorisent la réflexion sur les méthodes dans le langage, où ces méthodes souhaitent avoir un moyen de représenter le type de retour d’une méthode quelconque, y compris les méthodes void, avec une instance de 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.

L’opérateur typeof peut être utilisé sur un paramètre de type.The typeof operator can be used on a type parameter. Le résultat est l’objet System.Type pour le type au moment de l’exécution qui a été lié au paramètre de type.The result is the System.Type object for the run-time type that was bound to the type parameter. L’opérateur typeof peut également être utilisé sur un type construit ou un type générique indépendant (types liés et indépendants).The typeof operator can also be used on a constructed type or an unbound generic type (Bound and unbound types). L’objet System.Type pour un type générique indépendant n’est pas le même que l’objet System.Type du type d’instance.The System.Type object for an unbound generic type is not the same as the System.Type object of the instance type. Le type d’instance est toujours un type construit fermé au moment de l’exécution, de sorte que son objet System.Type dépend des arguments de type au moment de l’exécution en cours d’utilisation, tandis que le type générique indépendant n’a aucun argument de type.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.

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

produit la sortie suivante :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]

Notez que int et System.Int32 sont du même type.Note that int and System.Int32 are the same type.

Notez également que le résultat de typeof(X<>) ne dépend pas de l’argument de type, mais le résultat de 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.

Opérateurs vérifiés et non vérifiésThe checked and unchecked operators

Les opérateurs checked et unchecked permettent de contrôler le contexte de contrôle de dépassement de capacité pour les opérations arithmétiques de type intégral et les conversions.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 ')'
    ;

L’opérateur checked évalue l’expression contenue dans un contexte vérifié, tandis que l’opérateur unchecked évalue l’expression contenue dans un contexte non vérifié.The checked operator evaluates the contained expression in a checked context, and the unchecked operator evaluates the contained expression in an unchecked context. Un checked_expression ou un unchecked_expression correspond exactement à un parenthesized_expression (expressions entre parenthèses), sauf que l’expression contenue est évaluée dans le contexte de vérification de dépassement de capacité donné .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.

Le contexte de contrôle de dépassement de capacité peut également être contrôlé par le biais des instructions checked et unchecked (les instructions checked et unchecked).The overflow checking context can also be controlled through the checked and unchecked statements (The checked and unchecked statements).

Les opérations suivantes sont affectées par le contexte de contrôle de dépassement de capacité établi par les opérateurs et instructions checked et unchecked :The following operations are affected by the overflow checking context established by the checked and unchecked operators and statements:

Lorsque l’une des opérations ci-dessus génère un résultat qui est trop grand pour être représenté dans le type de destination, le contexte dans lequel l’opération est effectuée contrôle le comportement résultant :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:

  • Dans un contexte checked, si l’opération est une expression constante (expressions constantes), une erreur de compilation se produit.In a checked context, if the operation is a constant expression (Constant expressions), a compile-time error occurs. Dans le cas contraire, lorsque l’opération est effectuée au moment de l’exécution, une System.OverflowException est levée.Otherwise, when the operation is performed at run-time, a System.OverflowException is thrown.
  • Dans un contexte unchecked, le résultat est tronqué en ignorant les bits de poids fort qui ne tiennent pas dans le type de destination.In an unchecked context, the result is truncated by discarding any high-order bits that do not fit in the destination type.

Pour les expressions non constantes (expressions évaluées au moment de l’exécution) qui ne sont pas encadrées par des opérateurs ou des instructions checked ou unchecked, le contexte de contrôle de dépassement de capacité par défaut est unchecked, sauf si des facteurs externes (tels que les commutateurs de compilateur et configuration de l’environnement d’exécution) appelez pour l’évaluation de l' checked.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.

Pour les expressions constantes (expressions qui peuvent être entièrement évaluées au moment de la compilation), le contexte de contrôle de dépassement de capacité par défaut est toujours checked.For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. À moins qu’une expression constante soit explicitement placée dans un contexte unchecked, les dépassements qui se produisent pendant l’évaluation de l’expression au moment de la compilation provoquent toujours des erreurs de compilation.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.

Le corps d’une fonction anonyme n’est pas affecté par les contextes checked ou unchecked dans lesquels la fonction anonyme se produit.The body of an anonymous function is not affected by checked or unchecked contexts in which the anonymous function occurs.

Dans l’exempleIn 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
    }
}

aucune erreur de compilation n’est signalée, car aucune des expressions ne peut être évaluée au moment de la compilation.no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. Au moment de l’exécution, la méthode F lève une System.OverflowException, et la méthode G retourne-727379968 (les 32 de poids faible du résultat hors limites).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). Le comportement de la méthode H dépend du contexte de vérification de dépassement de capacité par défaut pour la compilation, mais il est identique à F ou identique à 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.

Dans l’exempleIn 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
    }
}

les dépassements qui se produisent lors de l’évaluation des expressions constantes dans F et H provoquent le signalement des erreurs de compilation, car les expressions sont évaluées dans un contexte 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. Un dépassement de capacité se produit également lors de l’évaluation de l’expression constante dans G, mais étant donné que l’évaluation a lieu dans un contexte unchecked, le dépassement de capacité n’est pas signalé.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.

Les opérateurs checked et unchecked affectent uniquement le contexte de contrôle de dépassement de capacité pour les opérations qui sont textuellement contenues dans les jetons « ( » et « ) ».The checked and unchecked operators only affect the overflow checking context for those operations that are textually contained within the "(" and ")" tokens. Les opérateurs n’ont aucun effet sur les fonctions membres qui sont appelées suite à l’évaluation de l’expression contenue.The operators have no effect on function members that are invoked as a result of evaluating the contained expression. Dans l’exempleIn the example

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

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

l’utilisation de checked dans F n’affecte pas l’évaluation de x * y dans Multiply, donc x * y est évaluée dans le contexte de contrôle de dépassement de capacité par défaut.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.

L’opérateur unchecked est pratique lors de l’écriture de constantes des types intégraux signés en notation hexadécimale.The unchecked operator is convenient when writing constants of the signed integral types in hexadecimal notation. Exemple :For example:

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

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

Les deux constantes hexadécimales ci-dessus sont de type uint.Both of the hexadecimal constants above are of type uint. Étant donné que les constantes se trouvent en dehors de la plage int, sans l’opérateur unchecked, les casts en int produisent des erreurs de compilation.Because the constants are outside the int range, without the unchecked operator, the casts to int would produce compile-time errors.

Les opérateurs et les instructions checked et unchecked permettent aux programmeurs de contrôler certains aspects de certains calculs numériques.The checked and unchecked operators and statements allow programmers to control certain aspects of some numeric calculations. Toutefois, le comportement de certains opérateurs numériques dépend des types de données des opérandes.However, the behavior of some numeric operators depends on their operands' data types. Par exemple, la multiplication de deux décimales produit toujours une exception en cas de dépassement de capacité, même dans une construction explicitement unchecked.For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked construct. De même, la multiplication de deux valeurs float n’entraîne jamais d’exception en cas de dépassement de capacité, même dans une construction explicitement checked.Similarly, multiplying two floats never results in an exception on overflow even within an explicitly checked construct. En outre, les autres opérateurs ne sont jamais affectés par le mode de vérification, qu’il s’agisse d’une valeur par défaut ou explicite.In addition, other operators are never affected by the mode of checking, whether default or explicit.

expressions de valeur par défautDefault value expressions

Une expression de valeur par défaut est utilisée pour obtenir la valeur par défaut (valeurs par défaut) d’un type.A default value expression is used to obtain the default value (Default values) of a type. En général, une expression de valeur par défaut est utilisée pour les paramètres de type, car elle peut ne pas être connue si le paramètre de type est un type valeur ou un type référence.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. (Aucune conversion n’existe à partir du littéral null vers un paramètre de type, sauf si le paramètre de type est connu comme étant un type référence.)(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 ')'
    ;

Si le type d’un default_value_expression est évalué au moment de l’exécution sur un type référence, le résultat est null converti en ce type.If the type in a default_value_expression evaluates at run-time to a reference type, the result is null converted to that type. Si le type d’un default_value_expression est évalué au moment de l’exécution sur un type valeur, le résultat est la valeur par défaut de Value_type(constructeurs par défaut).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).

Un default_value_expression est une expression constante (expressions constantes) si le type est un type référence ou un paramètre de type qui est connu comme étant un type référence (contraintes de paramètre de type).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). En outre, un default_value_expression est une expression constante si le type est l’un des types de valeurs suivants : sbyte, byte, short, ushort, int, uint, long, ulong, char, 0, 1, 2, 3 , ou n’importe quel type énumération.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.

Expressions NameofNameof expressions

Un nameof_expression est utilisé pour obtenir le nom d’une entité de programme sous la forme d’une chaîne constante.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
    ;

Par programmation, l’opérande named_entity est toujours une expression.Grammatically speaking, the named_entity operand is always an expression. Étant donné que nameof n’est pas un mot clé réservé, une expression nameof est toujours ambiguë syntaxiquement avec un appel du nom simple nameof.Because nameof is not a reserved keyword, a nameof expression is always syntactically ambiguous with an invocation of the simple name nameof. Pour des raisons de compatibilité, si une recherche de nom (noms simples) du nom nameof aboutit, l’expression est traitée comme un invocation_expression , que l’appel soit légal ou non.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. Dans le cas contraire, il s’agit d’un nameof_expression.Otherwise it is a nameof_expression.

La signification de la named_entity d’un nameof_expression est la signification de l’expression en tant qu’expression ; autrement dit, en tant que simple_name, base_access ou 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. Toutefois, lorsque la recherche décrite dans noms simples et accès aux membres génère une erreur parce qu’un membre d’instance a été trouvé dans un contexte statique, un nameof_expression ne produit aucune erreur de ce type.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.

Il s’agit d’une erreur de compilation pour un named_entity désignant un groupe de méthodes pour avoir un type_argument_list.It is a compile-time error for a named_entity designating a method group to have a type_argument_list. Il s’agit d’une erreur au moment de la compilation pour qu’un named_entity_target ait le type dynamic.It is a compile time error for a named_entity_target to have the type dynamic.

Un nameof_expression est une expression constante de type string et n’a aucun effet au moment de l’exécution.A nameof_expression is a constant expression of type string, and has no effect at runtime. Plus précisément, son named_entity n’est pas évalué et est ignoré pour les besoins de l’analyse de l’assignation définie (règles générales pour les expressions simples).Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). Sa valeur est le dernier identificateur du named_entity avant le type_argument_listfinal facultatif, transformé de la façon suivante :Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed in the following way:

  • Le préfixe@«», s’il est utilisé, est supprimé.The prefix "@", if used, is removed.
  • Chaque unicode_escape_sequence est transformée en son caractère Unicode correspondant.Each unicode_escape_sequence is transformed into its corresponding Unicode character.
  • Tous les formatting_characters sont supprimés.Any formatting_characters are removed.

Ce sont les mêmes transformations appliquées dans les identificateurs lors du test d’égalité entre les identificateurs.These are the same transformations applied in Identifiers when testing equality between identifiers.

TODO : exemplesTODO: examples

Expressions de méthode anonymesAnonymous method expressions

Un anonymous_method_expression est l’une des deux façons de définir une fonction anonyme.An anonymous_method_expression is one of two ways of defining an anonymous function. Celles-ci sont décrites plus en détail dans expressions de fonction anonymes.These are further described in Anonymous function expressions.

Les opérateurs unaires.Unary operators

Les opérateurs unaires ?, +, -, !, ~, ++, --, Cast et await sont appelés opérateurs unaires.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
    ;

Si l’opérande d’un unary_expression a le type au moment de la compilation dynamic, il est lié dynamiquement (liaison dynamique).If the operand of a unary_expression has the compile-time type dynamic, it is dynamically bound (Dynamic binding). Dans ce cas, le type au moment de la compilation du unary_expression est dynamic, et la résolution décrite ci-dessous aura lieu au moment de l’exécution à l’aide du type d’exécution de l’opérande.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.

Opérateur conditionnel nullNull-conditional operator

L’opérateur conditionnel null applique une liste d’opérations à son opérande uniquement si cet opérande n’a pas la valeur null.The null-conditional operator applies a list of operations to its operand only if that operand is non-null. Sinon, le résultat de l’application de l’opérateur est 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? ')'
    ;

La liste des opérations peut inclure l’accès au membre et les opérations d’accès aux éléments (qui peuvent eux-mêmes être conditionnels null), ainsi que l’appel.The list of operations can include member access and element access operations (which may themselves be null-conditional), as well as invocation.

Par exemple, l’expression a.b?[0]?.c() est un null_conditional_expression avec un primary_expression a.b et null_conditional_operations ?[0] (accès à l’élément conditionnel null), ?.c (membre conditionnel null Access) et () (appel).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).

Pour un null_conditional_expression E avec un primary_expression P, E0 est l’expression obtenue en supprimant textuellement le @no__t de début-5 de chaque null_conditional_operations de E qui en avoir un.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. D’un point de vue conceptuel, E0 est l’expression qui sera évaluée si aucune des vérifications null représentées par les ?s ne trouve de null.Conceptually, E0 is the expression that will be evaluated if none of the null checks represented by the ?s do find a null.

Par ailleurs, laissez E1 être l’expression obtenue en supprimant textuellement la ? de début à partir de la première null_conditional_operations dans E.Also, let E1 be the expression obtained by textually removing the leading ? from just the first of the null_conditional_operations in E. Cela peut aboutir à une expression primaire (s’il n’y avait qu’un seul ?) ou à un autre null_conditional_expression.This may lead to a primary-expression (if there was just one ?) or to another null_conditional_expression.

Par exemple, si E est l’expression a.b?[0]?.c(), E0 est l’expression a.b[0].c() et E1 est l’expression 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().

Si E0 est classifié comme Nothing, E est classé comme Nothing.If E0 is classified as nothing, then E is classified as nothing. Dans le cas contraire, E est classé comme une valeur.Otherwise E is classified as a value.

E0 et E1 sont utilisés pour déterminer la signification de E :E0 and E1 are used to determine the meaning of E:

  • Si E se produit en tant que statement_expression , la signification de E est identique à celle de l’instructionIf E occurs as a statement_expression the meaning of E is the same as the statement

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

    sauf que P n’est évalué qu’une seule fois.except that P is evaluated only once.

  • Sinon, si E0 est classé comme rien, une erreur de compilation se produit.Otherwise, if E0 is classified as nothing a compile-time error occurs.

  • Dans le cas contraire, laissez T0 le type de E0.Otherwise, let T0 be the type of E0.

    • Si T0 est un paramètre de type qui n’est pas connu comme étant un type référence ou un type valeur n’acceptant pas les valeurs NULL, une erreur de compilation se produit.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.

    • Si T0 est un type valeur n’acceptant pas les valeurs NULL, le type de E est T0?, et la signification de E est identique à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
      

      Hormis le fait que P n’est évalué qu’une seule fois.except that P is evaluated only once.

    • Dans le cas contraire, le type de E est T0, et la signification de E est la même queOtherwise the type of E is T0, and the meaning of E is the same as

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

      Hormis le fait que P n’est évalué qu’une seule fois.except that P is evaluated only once.

Si E1 est lui-même un null_conditional_expression, ces règles sont appliquées à nouveau, en imbriquant les tests pour null jusqu’à ce qu’il n’y ait plus de ?, et l’expression a été réduite jusqu’à l’expression primaire 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.

Par exemple, si l’expression a.b?[0]?.c() se produit sous la forme d’une instruction-expression, comme dans l’instruction :For example, if the expression a.b?[0]?.c() occurs as a statement-expression, as in the statement:

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

son sens est équivalent à :its meaning is equivalent to:

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

ce qui équivaut à :which again is equivalent to:

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

À ceci près que les a.b et a.b[0] ne sont évaluées qu’une seule fois.Except that a.b and a.b[0] are evaluated only once.

Si elle se produit dans un contexte où sa valeur est utilisée, comme dans :If it occurs in a context where its value is used, as in:

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

en partant du principe que le type de l’appel final n’est pas un type valeur non Nullable, son sens est équivalent à :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();

à ceci près que les a.b et a.b[0] ne sont évaluées qu’une seule fois.except that a.b and a.b[0] are evaluated only once.

Expressions conditionnelles null en tant qu’initialiseurs de projectionNull-conditional expressions as projection initializers

Une expression conditionnelle null est uniquement autorisée en tant que member_declarator dans un anonymous_object_creation_expression (expressions de création d’objet anonyme) si elle se termine par un accès au membre (éventuellement nullement conditionnel).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. Par programmation, cette exigence peut être exprimée comme suit :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?
    ;

Il s’agit d’un cas particulier de la grammaire pour null_conditional_expression ci-dessus.This is a special case of the grammar for null_conditional_expression above. La production pour member_declarator dans les expressions de création d’objet anonyme comprend alors uniquement null_conditional_member_access.The production for member_declarator in Anonymous object creation expressions then includes only null_conditional_member_access.

Expressions conditionnelles null en tant qu’expressions d’instructionNull-conditional expressions as statement expressions

Une expression conditionnelle null est uniquement autorisée comme statement_expression (instructions d'expression) si elle se termine par un appel.A null-conditional expression is only allowed as a statement_expression (Expression statements) if it ends with an invocation. Par programmation, cette exigence peut être exprimée comme suit :Grammatically, this requirement can be expressed as:

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

Il s’agit d’un cas particulier de la grammaire pour null_conditional_expression ci-dessus.This is a special case of the grammar for null_conditional_expression above. La production pour statement_expression dans les instructions d’expression comprend alors uniquement null_conditional_invocation_expression.The production for statement_expression in Expression statements then includes only null_conditional_invocation_expression.

Opérateur plus unaireUnary plus operator

Pour une opération de la forme +x, la résolution de surcharge d’opérateur unaire (résolution de surcharge d’opérateur unaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.For an operation of the form +x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. L’opérande est converti en type de paramètre de l’opérateur sélectionné et le type du résultat est le type de retour de l’opérateur.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. Les opérateurs plus unaires prédéfinis sont les suivants :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);

Pour chacun de ces opérateurs, le résultat est simplement la valeur de l’opérande.For each of these operators, the result is simply the value of the operand.

Opération moins unaireUnary minus operator

Pour une opération de la forme -x, la résolution de surcharge d’opérateur unaire (résolution de surcharge d’opérateur unaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.For an operation of the form -x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. L’opérande est converti en type de paramètre de l’opérateur sélectionné et le type du résultat est le type de retour de l’opérateur.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. Les opérateurs de négation prédéfinis sont les suivants :The predefined negation operators are:

  • Négation d’entier :Integer negation:

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

    Le résultat est calculé en soustrayant x de zéro.The result is computed by subtracting x from zero. Si la valeur de x est la plus petite valeur représentable du type d’opérande (-2 ^ 31 pour int ou-2 ^ 63 pour long), la négation mathématique de x n’est pas représentable dans le type d’opérande.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. Si cela se produit dans un contexte checked, une System.OverflowException est levée ; Si elle se produit dans un contexte unchecked, le résultat est la valeur de l’opérande et le dépassement de capacité n’est pas signalé.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.

    Si l’opérande de l’opérateur de négation est de type uint, il est converti en type long, et le type du résultat est 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. Une exception est la règle qui autorise l’écriture de la valeur int-2147483648 (-2 ^ 31) sous la forme d’un littéral d’entier décimal (littéraux entiers).An exception is the rule that permits the int value -2147483648 (-2^31) to be written as a decimal integer literal (Integer literals).

    Si l’opérande de l’opérateur de négation est de type ulong, une erreur de compilation se produit.If the operand of the negation operator is of type ulong, a compile-time error occurs. Une exception est la règle qui autorise l’écriture de la valeur long-9223372036854775808 (-2 ^ 63) sous la forme d’un littéral d’entier décimal (littéraux entiers).An exception is the rule that permits the long value -9223372036854775808 (-2^63) to be written as a decimal integer literal (Integer literals).

  • Négation à virgule flottante :Floating-point negation:

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

    Le résultat est la valeur de x avec son signe inversé.The result is the value of x with its sign inverted. Si x est NaN, le résultat est également NaN.If x is NaN, the result is also NaN.

  • Négation décimale :Decimal negation:

    decimal operator -(decimal x);
    

    Le résultat est calculé en soustrayant x de zéro.The result is computed by subtracting x from zero. La négation décimale équivaut à utiliser l’opérateur moins unaire de type System.Decimal.Decimal negation is equivalent to using the unary minus operator of type System.Decimal.

Opérateur de négation logiqueLogical negation operator

Pour une opération de la forme !x, la résolution de surcharge d’opérateur unaire (résolution de surcharge d’opérateur unaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.For an operation of the form !x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. L’opérande est converti en type de paramètre de l’opérateur sélectionné et le type du résultat est le type de retour de l’opérateur.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. Il n’existe qu’un seul opérateur de négation logique prédéfini :Only one predefined logical negation operator exists:

bool operator !(bool x);

Cet opérateur calcule la négation logique de l’opérande : Si l’opérande est true, le résultat est false.This operator computes the logical negation of the operand: If the operand is true, the result is false. Si l’opérande est false, le résultat est true.If the operand is false, the result is true.

Opérateur de complément de bitsBitwise complement operator

Pour une opération de la forme ~x, la résolution de surcharge d’opérateur unaire (résolution de surcharge d’opérateur unaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.For an operation of the form ~x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. L’opérande est converti en type de paramètre de l’opérateur sélectionné et le type du résultat est le type de retour de l’opérateur.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. Les opérateurs de complément de bits prédéfinis sont les suivants :The predefined bitwise complement operators are:

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

Pour chacun de ces opérateurs, le résultat de l’opération est le complément de bits de x.For each of these operators, the result of the operation is the bitwise complement of x.

Chaque type d’énumération E fournit implicitement l’opérateur de complément de bits suivant :Every enumeration type E implicitly provides the following bitwise complement operator:

E operator ~(E x);

Le résultat de l’évaluation de ~x, où x est une expression d’un type d’énumération E avec un type sous-jacent U, est exactement le même que l’évaluation de (E)(~(U)x), sauf que la conversion en E est toujours effectuée comme si dans un contexte unchecked ( Opérateurs activés et désactivés).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).

Opérateurs préfixés d’incrémentation et de décrémentationPrefix increment and decrement operators

pre_increment_expression
    : '++' unary_expression
    ;

pre_decrement_expression
    : '--' unary_expression
    ;

L’opérande d’une opération d’incrémentation ou de décrémentation de préfixe doit être une expression classifiée comme une variable, un accès à une propriété ou un accès à un indexeur.The operand of a prefix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Le résultat de l’opération est une valeur du même type que l’opérande.The result of the operation is a value of the same type as the operand.

Si l’opérande d’une opération d’incrémentation ou de décrémentation de préfixe est un accès à une propriété ou un indexeur, la propriété ou l’indexeur doit avoir à la fois un accesseur get et un accesseur set.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. Si ce n’est pas le cas, une erreur de temps de liaison se produit.If this is not the case, a binding-time error occurs.

La résolution de surcharge d’opérateur unaire (résolution de surcharge d’opérateur unaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Les opérateurs prédéfinis ++ et -- existent pour les types suivants : sbyte, byte, short, ushort, int, uint, long, ulong, 0, 1, 2, 3 et tout type enum.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Les opérateurs ++ prédéfinis retournent la valeur produite par l’ajout de 1 à l’opérande, et les opérateurs -- prédéfinis retournent la valeur produite par la soustraction de 1 de l’opérande.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. Dans un contexte checked, si le résultat de cet ajout ou de cette soustraction est en dehors de la plage du type de résultat et que le type de résultat est un type intégral ou un type enum, une System.OverflowException est levée.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.

Le traitement au moment de l’exécution d’une opération de préfixe d’incrémentation ou de décrémentation de la forme ++x ou --x se compose des étapes suivantes :The run-time processing of a prefix increment or decrement operation of the form ++x or --x consists of the following steps:

  • Si x est classée en tant que variable :If x is classified as a variable:
    • x est évaluée pour produire la variable.x is evaluated to produce the variable.
    • L’opérateur sélectionné est appelé avec la valeur de x comme argument.The selected operator is invoked with the value of x as its argument.
    • La valeur retournée par l’opérateur est stockée dans l’emplacement donné par l’évaluation de x.The value returned by the operator is stored in the location given by the evaluation of x.
    • La valeur retournée par l’opérateur devient le résultat de l’opération.The value returned by the operator becomes the result of the operation.
  • Si x est classé comme un accès à une propriété ou un indexeur :If x is classified as a property or indexer access:
    • L’expression d’instance (si x n’est pas static) et la liste d’arguments (si x est un accès à un indexeur) associée à x sont évaluées, et les résultats sont utilisés dans les appels d’accesseur get et set suivants.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.
    • L’accesseur get de x est appelé.The get accessor of x is invoked.
    • L’opérateur sélectionné est appelé avec la valeur retournée par l’accesseur get comme argument.The selected operator is invoked with the value returned by the get accessor as its argument.
    • L’accesseur set de x est appelé avec la valeur retournée par l’opérateur comme argument value.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • La valeur retournée par l’opérateur devient le résultat de l’opération.The value returned by the operator becomes the result of the operation.

Les opérateurs ++ et -- prennent également en charge la notation suffixée (opérateurs d’incrémentation et de décrémentation suffixés).The ++ and -- operators also support postfix notation (Postfix increment and decrement operators). En général, le résultat de x++ ou x-- est la valeur de x avant l’opération, alors que le résultat de ++x ou --x est la valeur de x après l’opération.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. Dans les deux cas, x lui-même a la même valeur après l’opération.In either case, x itself has the same value after the operation.

Une implémentation operator++ ou operator-- peut être appelée à l’aide de la notation postfix ou préfixe.An operator++ or operator-- implementation can be invoked using either postfix or prefix notation. Il n’est pas possible d’avoir des implémentations d’opérateur distinctes pour les deux notations.It is not possible to have separate operator implementations for the two notations.

Expressions de castCast expressions

Un cast_expression est utilisé pour convertir explicitement une expression en un type donné.A cast_expression is used to explicitly convert an expression to a given type.

cast_expression
    : '(' type ')' unary_expression
    ;

Un cast_expression de la forme (T)E, où T est un type et E est un unary_expression, effectue une conversion explicite (conversions explicites) de la valeur de E en type 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. S’il n’existe aucune conversion explicite de E à T, une erreur de liaison au moment de la liaison se produit.If no explicit conversion exists from E to T, a binding-time error occurs. Dans le cas contraire, le résultat est la valeur produite par la conversion explicite.Otherwise, the result is the value produced by the explicit conversion. Le résultat est toujours classifié comme une valeur, même si E désigne une variable.The result is always classified as a value, even if E denotes a variable.

La grammaire d’un cast_expression provoque certaines ambiguïtés syntaxiques.The grammar for a cast_expression leads to certain syntactic ambiguities. Par exemple, l’expression (x)-y peut être interprétée comme un cast_expression (un cast de -y en type x) ou en tant que additive_expression combiné avec un parenthesized_expression (qui calcule la valeur 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).

Pour résoudre les ambiguïtés cast_expression , la règle suivante existe : Une séquence d’un ou plusieurs jetons(espaces blancs) entre parenthèses est considérée comme le début d’un cast_expression uniquement si au moins l’une des conditions suivantes est vraie :To resolve cast_expression ambiguities, the following rule exists: A sequence of one or more tokens (White space) enclosed in parentheses is considered the start of a cast_expression only if at least one of the following are true:

  • La séquence de jetons est une grammaire correcte pour un type, mais pas pour une expression.The sequence of tokens is correct grammar for a type, but not for an expression.
  • La séquence de jetons est une grammaire correcte pour un type, et le jeton qui suit immédiatement les parenthèses fermantes est le jeton « ~ », le jeton « ! », le jeton « ( », un identificateur (séquences d’échappement de caractère Unicode ), un littéral (littéraux) ou tout mot clé (mots clés), à l’exception de 0 et 1.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.

Le terme « grammaire correcte » ci-dessus signifie uniquement que la séquence de jetons doit se conformer à la production grammaticale particulière.The term "correct grammar" above means only that the sequence of tokens must conform to the particular grammatical production. Elle ne tient pas compte de la signification réelle des identificateurs constitutifs.It specifically does not consider the actual meaning of any constituent identifiers. Par exemple, si x et y sont des identificateurs, x.y est une grammaire correcte pour un type, même si x.y ne désigne pas un type.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.

À partir de la règle de désambiguation, elle suit que, si x et y sont des identificateurs, (x)y, (x)(y) et (x)(-y) sont cast_expression, mais (x)-y ne l’est pas, même si x identifie un type.From the disambiguation rule it follows that, if x and y are identifiers, (x)y, (x)(y), and (x)(-y) are cast_expressions, but (x)-y is not, even if x identifies a type. Toutefois, si x est un mot clé qui identifie un type prédéfini (tel que int), les quatre formes sont cast_expressions (car ce mot clé n’est peut-être pas une expression par lui-même).However, if x is a keyword that identifies a predefined type (such as int), then all four forms are cast_expressions (because such a keyword could not possibly be an expression by itself).

Expressions awaitAwait expressions

L’opérateur await est utilisé pour interrompre l’évaluation de la fonction Async englobante jusqu’à ce que l’opération asynchrone représentée par l’opérande soit terminée.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
    ;

Un await_expression est uniquement autorisé dans le corps d’une fonction Async (itérateurs).An await_expression is only allowed in the body of an async function (Iterators). Dans la fonction Async englobante la plus proche, un await_expression peut ne pas se produire aux emplacements suivants :Within the nearest enclosing async function, an await_expression may not occur in these places:

  • Dans une fonction anonyme imbriquée (non asynchrone)Inside a nested (non-async) anonymous function
  • À l’intérieur du bloc d’un lock_statementInside the block of a lock_statement
  • Dans un contexte non sécuriséIn an unsafe context

Notez qu’un await_expression ne peut pas se produire à la plupart des emplacements d’un query_expression, car ceux-ci sont convertis de façon syntaxique pour utiliser des expressions lambda non asynchrones.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.

À l’intérieur d’une fonction Async, await ne peut pas être utilisé en tant qu’identificateur.Inside of an async function, await cannot be used as an identifier. Il n’y a donc pas d’ambiguïté syntaxique entre await-expressions et diverses expressions impliquant des identificateurs.There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. En dehors des fonctions Async, await agit comme un identificateur normal.Outside of async functions, await acts as a normal identifier.

L’opérande d’un await_expression est appelé la tâche.The operand of an await_expression is called the task. Il représente une opération asynchrone qui peut ou ne peut pas être effectuée au moment où le await_expression est évalué.It represents an asynchronous operation that may or may not be complete at the time the await_expression is evaluated. L’objectif de l’opérateur await est de suspendre l’exécution de la fonction Async englobante jusqu’à ce que la tâche attendue soit terminée, puis d’obtenir son résultat.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.

Expressions awaitAwaitable expressions

La tâche d’une expression await doit être attendue.The task of an await expression is required to be awaitable. Une expression t est await si l’un des éléments suivants est attendu :An expression t is awaitable if one of the following holds:

  • t est du type au moment de la compilation dynamict is of compile time type dynamic
  • t a une instance accessible ou une méthode d’extension appelée GetAwaiter sans paramètres ni aucun paramètre de type, et un type de retour A pour lequel tous les éléments suivants sont détenus :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 implémente l’interface System.Runtime.CompilerServices.INotifyCompletion (ci-après dénommées INotifyCompletion pour des concisions)A implements the interface System.Runtime.CompilerServices.INotifyCompletion (hereafter known as INotifyCompletion for brevity)
    • A a une propriété d’instance accessible accessible en lecture IsCompleted de type boolA has an accessible, readable instance property IsCompleted of type bool
    • A a une méthode d’instance accessible GetResult sans paramètres et sans paramètres de typeA has an accessible instance method GetResult with no parameters and no type parameters

L’objectif de la méthode GetAwaiter est d’obtenir un await pour la tâche.The purpose of the GetAwaiter method is to obtain an awaiter for the task. Le type A est appelé type d’attente pour l’expression await.The type A is called the awaiter type for the await expression.

L’objectif de la propriété IsCompleted est de déterminer si la tâche est déjà terminée.The purpose of the IsCompleted property is to determine if the task is already complete. Dans ce cas, il n’est pas nécessaire d’interrompre l’évaluation.If so, there is no need to suspend evaluation.

L’objectif de la méthode INotifyCompletion.OnCompleted consiste à inscrire une « continuation » à la tâche ; c’est-à-dire un délégué (de type System.Action) qui sera appelé une fois la tâche terminée.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.

L’objectif de la méthode GetResult est d’obtenir le résultat de la tâche une fois qu’elle est terminée.The purpose of the GetResult method is to obtain the outcome of the task once it is complete. Ce résultat peut être terminé avec succès, éventuellement avec une valeur de résultat, ou il peut s’agir d’une exception levée par la méthode 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.

Classification des expressions awaitClassification of await expressions

L’expression await t est classée de la même façon que l’expression (t).GetAwaiter().GetResult().The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Ainsi, si le type de retour de GetResult est void, await_expression est classé comme Nothing.Thus, if the return type of GetResult is void, the await_expression is classified as nothing. S’il a un type de retour non void T, await_expression est classé comme une valeur de type T.If it has a non-void return type T, the await_expression is classified as a value of type T.

Évaluation du runtime des expressions awaitRuntime evaluation of await expressions

Au moment de l’exécution, l’expression await t est évaluée comme suit :At runtime, the expression await t is evaluated as follows:

  • Un await a est obtenu en évaluant l’expression (t).GetAwaiter().An awaiter a is obtained by evaluating the expression (t).GetAwaiter().
  • Un bool b est obtenu en évaluant l’expression (a).IsCompleted.A bool b is obtained by evaluating the expression (a).IsCompleted.
  • Si b est false, l’évaluation varie selon que a implémente l’interface System.Runtime.CompilerServices.ICriticalNotifyCompletion (ci-après, appelée ICriticalNotifyCompletion pour plus de concision).If b is false then evaluation depends on whether a implements the interface System.Runtime.CompilerServices.ICriticalNotifyCompletion (hereafter known as ICriticalNotifyCompletion for brevity). Cette vérification s’effectue au moment de la liaison. par exemple, lors de l’exécution, si a a le type au moment de la compilation dynamic et au moment de la compilation, sinon.This check is done at binding time; i.e. at runtime if a has the compile time type dynamic, and at compile time otherwise. Laissez r désigner le délégué de reprise (itérateurs) :Let r denote the resumption delegate (Iterators):
    • Si a n’implémente pas ICriticalNotifyCompletion, l’expression (a as (INotifyCompletion)).OnCompleted(r) est évaluée.If a does not implement ICriticalNotifyCompletion, then the expression (a as (INotifyCompletion)).OnCompleted(r) is evaluated.
    • Si a implémente ICriticalNotifyCompletion, l’expression (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) est évaluée.If a does implement ICriticalNotifyCompletion, then the expression (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) is evaluated.
    • L’évaluation est ensuite interrompue et le contrôle est retourné à l’appelant actuel de la fonction Async.Evaluation is then suspended, and control is returned to the current caller of the async function.
  • Soit immédiatement après (si b était true), soit lors de l’appel ultérieur du délégué de reprise (si b était false), l’expression (a).GetResult() est évaluée.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. Si elle retourne une valeur, cette valeur est le résultat de await_expression.If it returns a value, that value is the result of the await_expression. Sinon, le résultat est Nothing.Otherwise the result is nothing.

Une implémentation de l’expression await des méthodes d’interface INotifyCompletion.OnCompleted et ICriticalNotifyCompletion.UnsafeOnCompleted doit entraîner l’appel de la méthode Delegate r au plus une fois.An awaiter's implementation of the interface methods INotifyCompletion.OnCompleted and ICriticalNotifyCompletion.UnsafeOnCompleted should cause the delegate r to be invoked at most once. Dans le cas contraire, le comportement de la fonction Async englobante n’est pas défini.Otherwise, the behavior of the enclosing async function is undefined.

Opérateurs arithmétiquesArithmetic operators

Les opérateurs arithmétiques *, /, %, + et -.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
    ;

Si un opérande d’un opérateur arithmétique a le type au moment de la compilation dynamic, l’expression est liée dynamiquement (liaison dynamique).If an operand of an arithmetic operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Dans ce cas, le type au moment de la compilation de l’expression est dynamic, et la résolution décrite ci-dessous a lieu au moment de l’exécution en utilisant le type d’exécution des opérandes qui ont le type au moment de la compilation 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.

Opérateur de multiplicationMultiplication operator

Pour une opération de la forme x * y, la résolution de surcharge d’opérateur binaire (résolution de surcharge d’opérateur binaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.For an operation of the form x * y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Les opérandes sont convertis en types de paramètre de l’opérateur sélectionné, et le type du résultat est le type de retour de l’opérateur.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.

Les opérateurs de multiplication prédéfinis sont répertoriés ci-dessous.The predefined multiplication operators are listed below. Les opérateurs calculent tous le produit de x et y.The operators all compute the product of x and y.

  • Multiplication d’entiers :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);
    

    Dans un contexte checked, si le produit est en dehors de la plage du type de résultat, une System.OverflowException est levée.In a checked context, if the product is outside the range of the result type, a System.OverflowException is thrown. Dans un contexte unchecked, les dépassements de capacité ne sont pas signalés et les bits de poids fort significatifs en dehors de la plage du type de résultat sont ignorés.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Multiplication à virgule flottante :Floating-point multiplication:

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

    Le produit est calculé en fonction des règles de l’arithmétique IEEE 754.The product is computed according to the rules of IEEE 754 arithmetic. Le tableau suivant répertorie les résultats de toutes les combinaisons possibles de valeurs finies différentes de zéro, de zéros, d’infinis et de NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Dans le tableau, x et y sont des valeurs finies positives.In the table, x and y are positive finite values. z est le résultat de x * y.z is the result of x * y. Si le résultat est trop grand pour le type de destination, z est l’infini.If the result is too large for the destination type, z is infinity. Si le résultat est trop petit pour le type de destination, z est égal à zéro.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
  • Multiplication décimale :Decimal multiplication:

    decimal operator *(decimal x, decimal y);
    

    Si la valeur résultante est trop grande pour être représentée au format decimal, une System.OverflowException est levée.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Si la valeur de résultat est trop petite pour être représentée au format decimal, le résultat est égal à zéro.If the result value is too small to represent in the decimal format, the result is zero. L’échelle du résultat, avant tout arrondi, est la somme des échelles des deux opérandes.The scale of the result, before any rounding, is the sum of the scales of the two operands.

    La multiplication décimale équivaut à utiliser l’opérateur de multiplication de type System.Decimal.Decimal multiplication is equivalent to using the multiplication operator of type System.Decimal.

Opérateur de divisionDivision operator

Pour une opération de la forme x / y, la résolution de surcharge d’opérateur binaire (résolution de surcharge d’opérateur binaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.For an operation of the form x / y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Les opérandes sont convertis en types de paramètre de l’opérateur sélectionné, et le type du résultat est le type de retour de l’opérateur.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.

Les opérateurs de division prédéfinis sont répertoriés ci-dessous.The predefined division operators are listed below. Les opérateurs calculent tous le quotient de x et y.The operators all compute the quotient of x and y.

  • Division d’entier :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);
    

    Si la valeur de l’opérande de droite est égale à zéro, une System.DivideByZeroException est levée.If the value of the right operand is zero, a System.DivideByZeroException is thrown.

    La Division arrondit le résultat vers zéro.The division rounds the result towards zero. Par conséquent, la valeur absolue du résultat est le plus grand entier possible qui est inférieur ou égal à la valeur absolue du quotient des deux opérandes.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. Le résultat est zéro ou positif lorsque les deux opérandes ont le même signe et zéro ou une valeur négative lorsque les deux opérandes ont des signes opposés.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.

    Si l’opérande de gauche est la valeur la plus petite représentable int ou long et que l’opérande de droite est -1, un dépassement de capacité se produit.If the left operand is the smallest representable int or long value and the right operand is -1, an overflow occurs. Dans un contexte checked, cela entraîne la levée d’une System.ArithmeticException (ou d’une sous-classe).In a checked context, this causes a System.ArithmeticException (or a subclass thereof) to be thrown. Dans un contexte unchecked, il est défini par l’implémentation pour déterminer si une System.ArithmeticException (ou une sous-classe de celle-ci) est levée ou si le dépassement de capacité n’est pas signalé avec la valeur résultante qui est celle de l’opérande de gauche.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.

  • Division à virgule flottante :Floating-point division:

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

    Le quotient est calculé en fonction des règles de l’arithmétique IEEE 754.The quotient is computed according to the rules of IEEE 754 arithmetic. Le tableau suivant répertorie les résultats de toutes les combinaisons possibles de valeurs finies différentes de zéro, de zéros, d’infinis et de NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Dans le tableau, x et y sont des valeurs finies positives.In the table, x and y are positive finite values. z est le résultat de x / y.z is the result of x / y. Si le résultat est trop grand pour le type de destination, z est l’infini.If the result is too large for the destination type, z is infinity. Si le résultat est trop petit pour le type de destination, z est égal à zéro.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
  • Division décimale :Decimal division:

    decimal operator /(decimal x, decimal y);
    

    Si la valeur de l’opérande de droite est égale à zéro, une System.DivideByZeroException est levée.If the value of the right operand is zero, a System.DivideByZeroException is thrown. Si la valeur résultante est trop grande pour être représentée au format decimal, une System.OverflowException est levée.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Si la valeur de résultat est trop petite pour être représentée au format decimal, le résultat est égal à zéro.If the result value is too small to represent in the decimal format, the result is zero. L’échelle du résultat est la plus petite échelle qui conserve un résultat égal à la valeur décimale représentable la plus proche du résultat mathématique vrai.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.

    La Division décimale équivaut à utiliser l’opérateur de division de type System.Decimal.Decimal division is equivalent to using the division operator of type System.Decimal.

Opérateur de resteRemainder operator

Pour une opération de la forme x % y, la résolution de surcharge d’opérateur binaire (résolution de surcharge d’opérateur binaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.For an operation of the form x % y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Les opérandes sont convertis en types de paramètre de l’opérateur sélectionné, et le type du résultat est le type de retour de l’opérateur.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.

Les opérateurs de reste prédéfinis sont répertoriés ci-dessous.The predefined remainder operators are listed below. Les opérateurs calculent tous le reste de la division entre x et y.The operators all compute the remainder of the division between x and y.

  • Reste entier :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);
    

    Le résultat de x % y est la valeur produite par x - (x / y) * y.The result of x % y is the value produced by x - (x / y) * y. Si y est égal à zéro, une System.DivideByZeroException est levée.If y is zero, a System.DivideByZeroException is thrown.

    Si l’opérande de gauche est la plus petite int ou long et que l’opérande de droite est -1, une System.OverflowException est levée.If the left operand is the smallest int or long value and the right operand is -1, a System.OverflowException is thrown. Dans le cas contraire, x % y lève une exception lorsque x / y ne lève pas d’exception.In no case does x % y throw an exception where x / y would not throw an exception.

  • Reste à virgule flottante :Floating-point remainder:

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

    Le tableau suivant répertorie les résultats de toutes les combinaisons possibles de valeurs finies différentes de zéro, de zéros, d’infinis et de NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Dans le tableau, x et y sont des valeurs finies positives.In the table, x and y are positive finite values. z est le résultat de x % y et est calculé comme x - n * y, où n est le plus grand entier possible inférieur ou égal à 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. Cette méthode de calcul du reste est analogue à celle utilisée pour les opérandes entiers, mais diffère de la définition IEEE 754 (dans laquelle n est l’entier le plus proche de 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
  • Reste décimal :Decimal remainder:

    decimal operator %(decimal x, decimal y);
    

    Si la valeur de l’opérande de droite est égale à zéro, une System.DivideByZeroException est levée.If the value of the right operand is zero, a System.DivideByZeroException is thrown. L’échelle du résultat, avant tout arrondi, est la plus grande des échelles des deux opérandes, et le signe du résultat, s’il est différent de zéro, est le même que celui de 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.

    Le reste décimal est équivalent à l’utilisation de l’opérateur de reste de type System.Decimal.Decimal remainder is equivalent to using the remainder operator of type System.Decimal.

Opérateur d’additionAddition operator

Pour une opération de la forme x + y, la résolution de surcharge d’opérateur binaire (résolution de surcharge d’opérateur binaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.For an operation of the form x + y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Les opérandes sont convertis en types de paramètre de l’opérateur sélectionné, et le type du résultat est le type de retour de l’opérateur.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.

Les opérateurs d’addition prédéfinis sont répertoriés ci-dessous.The predefined addition operators are listed below. Pour les types numériques et d’énumération, les opérateurs d’addition prédéfinis calculent la somme des deux opérandes.For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. Quand l’un des opérandes ou les deux sont de type chaîne, les opérateurs d’addition prédéfinis concatènent la représentation sous forme de chaîne des opérandes.When one or both operands are of type string, the predefined addition operators concatenate the string representation of the operands.

  • Ajout d’un entier :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);
    

    Dans un contexte checked, si la somme est en dehors de la plage du type de résultat, une System.OverflowException est levée.In a checked context, if the sum is outside the range of the result type, a System.OverflowException is thrown. Dans un contexte unchecked, les dépassements de capacité ne sont pas signalés et les bits de poids fort significatifs en dehors de la plage du type de résultat sont ignorés.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Addition à virgule flottante :Floating-point addition:

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

    La somme est calculée en fonction des règles de l’arithmétique IEEE 754.The sum is computed according to the rules of IEEE 754 arithmetic. Le tableau suivant répertorie les résultats de toutes les combinaisons possibles de valeurs finies différentes de zéro, de zéros, d’infinis et de NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Dans le tableau, x et y sont des valeurs finies non nulles, et z est le résultat de x + y.In the table, x and y are nonzero finite values, and z is the result of x + y. Si x et que y ont la même amplitude mais des signes opposés, z est un zéro positif.If x and y have the same magnitude but opposite signs, z is positive zero. Si x + y est trop grand pour être représenté dans le type de destination, z est un infini avec le même signe que 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.

    oy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    xx ez xx xx +inf+inf -inf-inf NaNNaN
    +0+0 oy +0+0 +0+0 +inf+inf -inf-inf NaNNaN
    -0-0 oy +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
  • Addition de nombres décimaux :Decimal addition:

    decimal operator +(decimal x, decimal y);
    

    Si la valeur résultante est trop grande pour être représentée au format decimal, une System.OverflowException est levée.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. L’échelle du résultat, avant tout arrondi, est la plus grande des échelles des deux opérandes.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    L’addition décimale équivaut à utiliser l’opérateur d’addition de type System.Decimal.Decimal addition is equivalent to using the addition operator of type System.Decimal.

  • Addition d’énumération.Enumeration addition. Chaque type d’énumération fournit implicitement les opérateurs prédéfinis suivants, où E est le type enum, et U est le type sous-jacent de 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);
    

    Au moment de l’exécution, ces opérateurs sont évalués exactement comme (E)((U)x + (U)y).At run-time these operators are evaluated exactly as (E)((U)x + (U)y).

  • Concaténation de chaînes :String concatenation:

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

    Ces surcharges de l’opérateur binaire + effectuent la concaténation de chaînes.These overloads of the binary + operator perform string concatenation. Si un opérande de concaténation de chaîne est null, une chaîne vide est substituée.If an operand of string concatenation is null, an empty string is substituted. Sinon, tout argument qui n’est pas une chaîne est converti en sa représentation sous forme de chaîne en appelant la méthode virtuelle ToString héritée du type object.Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. Si ToString retourne null, une chaîne vide est substituée.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
        }
    }
    

    Le résultat de l’opérateur de concaténation de chaînes est une chaîne qui se compose des caractères de l’opérande de gauche, suivis des caractères de l’opérande de droite. L’opérateur de concaténation de chaînes ne retourne jamais de valeur null. Une System.OutOfMemoryException peut être levée si la mémoire disponible est insuffisante pour allouer la chaîne résultante.A System.OutOfMemoryException may be thrown if there is not enough memory available to allocate the resulting string.

  • Combinaison de délégués.Delegate combination. Chaque type délégué fournit implicitement l’opérateur prédéfini suivant, où D est le type délégué :Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator +(D x, D y);
    

    L’opérateur binaire + effectue une combinaison de délégués lorsque les deux opérandes sont d’un type délégué D.The binary + operator performs delegate combination when both operands are of some delegate type D. (Si les opérandes ont des types délégués différents, une erreur de temps de liaison se produit.) Si le premier opérande est null, le résultat de l’opération est la valeur du deuxième opérande (même si c’est également 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). Sinon, si le second opérande est null, le résultat de l’opération est la valeur du premier opérande.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. Dans le cas contraire, le résultat de l’opération est une nouvelle instance de délégué qui, lorsqu’elle est appelée, appelle le premier opérande, puis appelle le second opérande.Otherwise, the result of the operation is a new delegate instance that, when invoked, invokes the first operand and then invokes the second operand. Pour obtenir des exemples de combinaison de délégués, consultez opérateur de soustraction et appel de délégué.For examples of delegate combination, see Subtraction operator and Delegate invocation. Étant donné que System.Delegate n’est pas un type délégué, operator @ no__t-2 n’est pas défini pour celui-ci.Since System.Delegate is not a delegate type, operator + is not defined for it.

Opérateur de soustractionSubtraction operator

Pour une opération de la forme x - y, la résolution de surcharge d’opérateur binaire (résolution de surcharge d’opérateur binaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.For an operation of the form x - y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Les opérandes sont convertis en types de paramètre de l’opérateur sélectionné, et le type du résultat est le type de retour de l’opérateur.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.

Les opérateurs de soustraction prédéfinis sont répertoriés ci-dessous.The predefined subtraction operators are listed below. Les opérateurs soustraitnt tous les y de x.The operators all subtract y from x.

  • Soustraction d’entiers :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);
    

    Dans un contexte checked, si la différence se situe en dehors de la plage du type de résultat, une System.OverflowException est levée.In a checked context, if the difference is outside the range of the result type, a System.OverflowException is thrown. Dans un contexte unchecked, les dépassements de capacité ne sont pas signalés et les bits de poids fort significatifs en dehors de la plage du type de résultat sont ignorés.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Soustraction à virgule flottante :Floating-point subtraction:

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

    La différence est calculée en fonction des règles de l’arithmétique IEEE 754.The difference is computed according to the rules of IEEE 754 arithmetic. Le tableau suivant répertorie les résultats de toutes les combinaisons possibles de valeurs finies différentes de zéro, de zéros, d’infinis et de valeurs NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaNs. Dans le tableau, x et y sont des valeurs finies non nulles, et z est le résultat de x - y.In the table, x and y are nonzero finite values, and z is the result of x - y. Si x et y sont égaux, z est un zéro positif.If x and y are equal, z is positive zero. Si x - y est trop grand pour être représenté dans le type de destination, z est un infini avec le même signe que 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.

    oy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    xx ez 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
  • Soustraction de décimale :Decimal subtraction:

    decimal operator -(decimal x, decimal y);
    

    Si la valeur résultante est trop grande pour être représentée au format decimal, une System.OverflowException est levée.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. L’échelle du résultat, avant tout arrondi, est la plus grande des échelles des deux opérandes.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    La soustraction de décimale équivaut à utiliser l’opérateur de soustraction de type System.Decimal.Decimal subtraction is equivalent to using the subtraction operator of type System.Decimal.

  • Soustraction d’énumération.Enumeration subtraction. Chaque type d’énumération fournit implicitement l’opérateur prédéfini suivant, où E est le type enum, et U est le type sous-jacent de 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);
    

    Cet opérateur est évalué exactement comme (U)((U)x - (U)y).This operator is evaluated exactly as (U)((U)x - (U)y). En d’autres termes, l’opérateur calcule la différence entre les valeurs ordinales de x et y, et le type du résultat est le type sous-jacent de l’énumération.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);
    

    Cet opérateur est évalué exactement comme (E)((U)x - y).This operator is evaluated exactly as (E)((U)x - y). En d’autres termes, l’opérateur soustrait une valeur du type sous-jacent de l’énumération, ce qui produit une valeur de l’énumération.In other words, the operator subtracts a value from the underlying type of the enumeration, yielding a value of the enumeration.

  • Suppression du délégué.Delegate removal. Chaque type délégué fournit implicitement l’opérateur prédéfini suivant, où D est le type délégué :Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator -(D x, D y);
    

    L’opérateur binaire - effectue une suppression de délégué lorsque les deux opérandes sont d’un type délégué D.The binary - operator performs delegate removal when both operands are of some delegate type D. Si les opérandes ont des types délégués différents, une erreur au moment de la liaison se produit.If the operands have different delegate types, a binding-time error occurs. Si le premier opérande a la valeur null, le résultat de l’opération est null.If the first operand is null, the result of the operation is null. Sinon, si le second opérande est null, le résultat de l’opération est la valeur du premier opérande.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. Sinon, les deux opérandes représentent les listes d’appel (déclarations de délégué) ayant une ou plusieurs entrées, et le résultat est une nouvelle liste d’appel comprenant la liste de la première opérande avec les entrées du deuxième opérande supprimées, à condition que la seconde la liste des opérandes est une sous-liste contiguë correcte du premier.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. (Pour déterminer l’égalité des sous-listes, les entrées correspondantes sont comparées à celles de l’opérateur d’égalité de délégué (opérateurs d’égalité de délégué).) Dans le cas contraire, le résultat est la valeur de l’opérande gauche.(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. Aucune des listes d’opérandes n’est modifiée dans le processus.Neither of the operands' lists is changed in the process. Si la liste du deuxième opérande correspond à plusieurs sous-listes d’entrées contiguës dans la liste du premier opérande, la sous-liste correspondante la plus à droite des entrées contiguës est supprimée.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. Si la suppression aboutit à une liste vide, le résultat est null.If removal results in an empty list, the result is null. Exemple :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
        }
    }
    

Opérateurs de décalageShift operators

Les opérateurs << et >> sont utilisés pour effectuer des opérations de décalage de bits.The << and >> operators are used to perform bit shifting operations.

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

Si un opérande d’un shift_expression a le type au moment de la compilation dynamic, l’expression est liée dynamiquement (liaison dynamique).If an operand of a shift_expression has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Dans ce cas, le type au moment de la compilation de l’expression est dynamic, et la résolution décrite ci-dessous a lieu au moment de l’exécution en utilisant le type d’exécution des opérandes qui ont le type au moment de la compilation 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.

Pour une opération de la forme x << count ou x >> count, la résolution de surcharge d’opérateur binaire (résolution de surcharge d’opérateur binaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.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. Les opérandes sont convertis en types de paramètre de l’opérateur sélectionné, et le type du résultat est le type de retour de l’opérateur.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.

Lors de la déclaration d’un opérateur de décalage surchargé, le type du premier opérande doit toujours être la classe ou le struct contenant la déclaration d’opérateur, et le type du second opérande doit toujours être 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.

Les opérateurs de décalage prédéfinis sont répertoriés ci-dessous.The predefined shift operators are listed below.

  • Décalage vers la gauche :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);
    

    L’opérateur << décale x vers la gauche d’un nombre de bits calculés comme décrit ci-dessous.The << operator shifts x left by a number of bits computed as described below.

    Les bits de poids fort en dehors de la plage du type de résultat de x sont ignorés, les bits restants sont décalés vers la gauche et les positions de bits vides de poids faible sont définies sur zéro.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.

  • Décalage vers la droite :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);
    

    L’opérateur >> décale x vers la droite d’un nombre de bits calculés comme décrit ci-dessous.The >> operator shifts x right by a number of bits computed as described below.

    Lorsque x est de type int ou long, les bits de poids faible de x sont ignorés, les bits restants sont décalés vers la droite et les positions de bits vides de poids fort ont la valeur zéro si x n’est pas négatif et a la valeur 1 si x est négatif.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.

    Lorsque x est de type uint ou ulong, les bits de poids faible de x sont ignorés, les bits restants sont décalés vers la droite et les positions de bits vides de poids fort ont la valeur zéro.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.

Pour les opérateurs prédéfinis, le nombre de bits à décaler est calculé comme suit :For the predefined operators, the number of bits to shift is computed as follows:

  • Lorsque le type de x est int ou uint, le nombre de décalages est donné par les cinq bits de poids faible de count.When the type of x is int or uint, the shift count is given by the low-order five bits of count. En d’autres termes, le nombre de décalages est calculé à partir de count & 0x1F.In other words, the shift count is computed from count & 0x1F.
  • Lorsque le type de x est long ou ulong, le nombre de décalages est donné par les six bits de poids faible de count.When the type of x is long or ulong, the shift count is given by the low-order six bits of count. En d’autres termes, le nombre de décalages est calculé à partir de count & 0x3F.In other words, the shift count is computed from count & 0x3F.

Si le nombre de décalages résultant est égal à zéro, les opérateurs de décalage retournent simplement la valeur de x.If the resulting shift count is zero, the shift operators simply return the value of x.

Les opérations de décalage ne provoquent jamais de dépassements de capacité et produisent les mêmes résultats dans les contextes checked et unchecked.Shift operations never cause overflows and produce the same results in checked and unchecked contexts.

Lorsque l’opérande gauche de l’opérateur >> est d’un type intégral signé, l’opérateur effectue un décalage arithmétique vers la droite, où la valeur du bit le plus significatif (le bit de signe) de l’opérande est propagée aux positions de bit vides de poids fort.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. Lorsque l’opérande gauche de l’opérateur >> est un type intégral non signé, l’opérateur effectue un décalage logique vers la droite où les positions de bits vides d’ordre élevé ont toujours la valeur zéro.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. Pour effectuer l’opération inverse de celle déduite du type d’opérande, vous pouvez utiliser des casts explicites.To perform the opposite operation of that inferred from the operand type, explicit casts can be used. Par exemple, si x est une variable de type int, l’opération unchecked((int)((uint)x >> y)) effectue un décalage logique à droite de 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.

Opérateurs relationnels et de test de typeRelational and type-testing operators

Les opérateurs ==, !=, <, >, <=, >=, is et as sont appelés opérateurs relationnels et de test de type.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
    ;

L’opérateur is est décrit dans l’opérateur is et l’opérateur as est décrit dans l’opérateur as.The is operator is described in The is operator and the as operator is described in The as operator.

Les opérateurs de comparaison==, !=, <, >, <= et >=.The ==, !=, <, >, <= and >= operators are comparison operators.

Si un opérande d’un opérateur de comparaison a le type au moment de la compilation dynamic, l’expression est liée dynamiquement (liaison dynamique).If an operand of a comparison operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Dans ce cas, le type au moment de la compilation de l’expression est dynamic, et la résolution décrite ci-dessous a lieu au moment de l’exécution en utilisant le type d’exécution des opérandes qui ont le type au moment de la compilation 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.

Pour une opération de la forme x op y, où op est un opérateur de comparaison, la résolution de surcharge (résolution de surcharge d’opérateur binaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.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. Les opérandes sont convertis en types de paramètre de l’opérateur sélectionné, et le type du résultat est le type de retour de l’opérateur.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.

Les opérateurs de comparaison prédéfinis sont décrits dans les sections suivantes.The predefined comparison operators are described in the following sections. Tous les opérateurs de comparaison prédéfinis retournent un résultat de type bool, comme décrit dans le tableau suivant.All predefined comparison operators return a result of type bool, as described in the following table.

OpérationOperation RésultatResult
x == y true si x est égal à y, false dans le cas contrairetrue if x is equal to y, false otherwise
x != y true si x n’est pas égal à y, false dans le cas contrairetrue if x is not equal to y, false otherwise
x < y true si la x est inférieure à y, false dans le cas contrairetrue if x is less than y, false otherwise
x > y true si x est supérieur à y, false dans le cas contrairetrue if x is greater than y, false otherwise
x <= y true si x est inférieur ou égal à y, false dans le cas contrairetrue if x is less than or equal to y, false otherwise
x >= y true si x est supérieur ou égal à y, false dans le cas contrairetrue if x is greater than or equal to y, false otherwise

Opérateurs de comparaison d’entiersInteger comparison operators

Les opérateurs de comparaison d’entiers prédéfinis sont les suivants :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);

Chacun de ces opérateurs compare les valeurs numériques des deux opérandes entiers et retourne une valeur bool qui indique si la relation particulière est true ou 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.

Opérateurs de comparaison de nombres à virgule flottanteFloating-point comparison operators

Les opérateurs de comparaison prédéfinis en virgule flottante sont les suivants :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);

Les opérateurs comparent les opérandes en fonction des règles de la norme IEEE 754 :The operators compare the operands according to the rules of the IEEE 754 standard:

  • Si l’un des opérandes est NaN, le résultat est false pour tous les opérateurs, à l’exception de !=, pour lesquels le résultat est true.If either operand is NaN, the result is false for all operators except !=, for which the result is true. Pour deux opérandes, x != y produit toujours le même résultat que !(x == y).For any two operands, x != y always produces the same result as !(x == y). Toutefois, lorsque l’un des opérandes ou les deux sont NaN, les opérateurs <, >, <= et >= ne produisent pas les mêmes résultats que la négation logique de l’opérateur opposé.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. Par exemple, si l’un des x et y est NaN, x < y est false, mais !(x >= y) est true.For example, if either of x and y is NaN, then x < y is false, but !(x >= y) is true.

  • Quand aucun des opérandes n’est NaN, les opérateurs comparent les valeurs des deux opérandes à virgule flottante en ce qui concerne le classement.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 et max sont les valeurs finies positives les plus petites et les plus grandes qui peuvent être représentées dans le format à virgule flottante donné.where min and max are the smallest and largest positive finite values that can be represented in the given floating-point format. Les effets notables de ce classement sont les suivants :Notable effects of this ordering are:

    • Les zéros positifs et négatifs sont considérés comme égaux.Negative and positive zeros are considered equal.
    • Un infini négatif est considéré comme inférieur à toutes les autres valeurs, mais égal à un autre infini négatif.A negative infinity is considered less than all other values, but equal to another negative infinity.
    • Un infini positif est considéré comme supérieur à toutes les autres valeurs, mais égal à un autre infini positif.A positive infinity is considered greater than all other values, but equal to another positive infinity.

Opérateurs de comparaison décimaleDecimal comparison operators

Les opérateurs de comparaison décimaux prédéfinis sont les suivants :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);

Chacun de ces opérateurs compare les valeurs numériques des deux opérandes décimaux et retourne une valeur bool qui indique si la relation particulière est true ou 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. Chaque comparaison décimale équivaut à utiliser l’opérateur relationnel ou d’égalité correspondant de type System.Decimal.Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal.

Opérateurs d’égalité booléennesBoolean equality operators

Les opérateurs d’égalité booléenne prédéfinis sont les suivants :The predefined boolean equality operators are:

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

Le résultat de == est true si x et y sont true ou si x et y sont false.The result of == is true if both x and y are true or if both x and y are false. Sinon, le résultat est false.Otherwise, the result is false.

Le résultat de != est false si x et y sont true ou si x et y sont false.The result of != is false if both x and y are true or if both x and y are false. Sinon, le résultat est true.Otherwise, the result is true. Quand les opérandes sont de type bool, l’opérateur != produit le même résultat que l’opérateur ^.When the operands are of type bool, the != operator produces the same result as the ^ operator.

Opérateurs de comparaison d’énumérationEnumeration comparison operators

Chaque type d’énumération fournit implicitement les opérateurs de comparaison prédéfinis suivants :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);

Le résultat de l’évaluation de x op y, où x et y sont des expressions d’un type énumération E avec un type sous-jacent U, et op est l’un des opérateurs de comparaison, est exactement le même que l’évaluation de ((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). En d’autres termes, les opérateurs de comparaison de type énumération comparent simplement les valeurs intégrales sous-jacentes des deux opérandes.In other words, the enumeration type comparison operators simply compare the underlying integral values of the two operands.

Opérateurs d’égalité de type référenceReference type equality operators

Les opérateurs d’égalité de type référence prédéfinis sont les suivants :The predefined reference type equality operators are:

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

Les opérateurs retournent le résultat de la comparaison des deux références pour l’égalité ou l’absence d’égalité.The operators return the result of comparing the two references for equality or non-equality.

Étant donné que les opérateurs d’égalité de type référence prédéfinis acceptent les opérandes de type object, ils s’appliquent à tous les types qui ne déclarent pas les membres operator == et operator != applicables.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. À l’inverse, tous les opérateurs d’égalité définis par l’utilisateur applicables masquent effectivement les opérateurs d’égalité de type référence prédéfinis.Conversely, any applicable user-defined equality operators effectively hide the predefined reference type equality operators.

Les opérateurs d’égalité de type référence prédéfinis nécessitent l’un des éléments suivants :The predefined reference type equality operators require one of the following:

  • Les deux opérandes sont une valeur d’un type connu comme étant un reference_type ou le littéral null.Both operands are a value of a type known to be a reference_type or the literal null. En outre, une conversion de référence explicite (conversions de références explicites) existe à partir du type de l’un des opérandes vers le type de l’autre opérande.Furthermore, an explicit reference conversion (Explicit reference conversions) exists from the type of either operand to the type of the other operand.
  • Un opérande est une valeur de type TT est un type_parameter et l’autre opérande est le littéral null.One operand is a value of type T where T is a type_parameter and the other operand is the literal null. En outre T n’a pas la contrainte de type valeur.Furthermore T does not have the value type constraint.

À moins que l’une de ces conditions ne soit vraie, une erreur de liaison au moment de la liaison se produit.Unless one of these conditions are true, a binding-time error occurs. Les implications notables de ces règles sont les suivantes :Notable implications of these rules are:

  • Il s’agit d’une erreur de liaison au moment de la liaison pour utiliser les opérateurs d’égalité de type référence prédéfinis pour comparer deux références qui sont connues pour être différentes au moment de la liaison.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. Par exemple, si les types au moment de la liaison des opérandes sont de deux types de classe A et B, et si ni A, ni B ne dérivent de l’autre, il serait impossible pour les deux opérandes de référencer le même objet.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. Ainsi, l’opération est considérée comme une erreur au moment de la liaison.Thus, the operation is considered a binding-time error.
  • Les opérateurs d’égalité de type référence prédéfinis n’autorisent pas la comparaison des opérandes de type valeur.The predefined reference type equality operators do not permit value type operands to be compared. Par conséquent, à moins qu’un type struct ne déclare ses propres opérateurs d’égalité, il n’est pas possible de comparer les valeurs de ce type struct.Therefore, unless a struct type declares its own equality operators, it is not possible to compare values of that struct type.
  • Les opérateurs d’égalité de type référence prédéfinis n’entraînent jamais la levée des opérations de boxing pour leurs opérandes.The predefined reference type equality operators never cause boxing operations to occur for their operands. Il serait inutile d’effectuer ces opérations de boxing, car les références aux instances boxed nouvellement allouées seraient nécessairement différentes de toutes les autres références.It would be meaningless to perform such boxing operations, since references to the newly allocated boxed instances would necessarily differ from all other references.
  • Si un opérande d’un type de paramètre de type T est comparé à null et que le type d’exécution de T est un type valeur, le résultat de la comparaison est 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.

L’exemple suivant vérifie si un argument d’un type de paramètre de type sans contrainte est 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();
        ...
    }
}

La construction x == null est autorisée même si T peut représenter un type valeur, et le résultat est simplement défini comme étant false lorsque T est un type valeur.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.

Pour une opération de la forme x == y ou x != y, s’il existe des operator == ou operator != applicables, les règles de résolution de surcharge d’opérateur (résolution de surcharge d’opérateur binaire) sélectionnent cet opérateur au lieu de l’égalité des types de références prédéfinis. and.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. Toutefois, il est toujours possible de sélectionner l’opérateur d’égalité de type référence prédéfini en effectuant un cast explicite de l’un des opérandes ou des deux en type 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. L’exempleThe 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);
    }
}

génère la sortieproduces the output

True
False
False
False

Les variables s et t font référence à deux instances string distinctes contenant les mêmes caractères.The s and t variables refer to two distinct string instances containing the same characters. La première comparaison génère True, car l’opérateur d’égalité de chaînes prédéfini (opérateurs d’égalité de chaînes) est sélectionné lorsque les deux opérandes sont de type string.The first comparison outputs True because the predefined string equality operator (String equality operators) is selected when both operands are of type string. Toutes les comparaisons restantes False, car l’opérateur d’égalité de type référence prédéfini est sélectionné lorsqu’au moins l’un des opérandes est de type 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.

Notez que la technique ci-dessus n’est pas significative pour les types valeur.Note that the above technique is not meaningful for value types. L’exempleThe example

class Test
{
    static void Main() {
        int i = 123;
        int j = 123;
        System.Console.WriteLine((object)i == (object)j);
    }
}

génère False, car les casts créent des références à deux instances distinctes de valeurs int boxed.outputs False because the casts create references to two separate instances of boxed int values.

Opérateurs d’égalité de chaînesString equality operators

Les opérateurs d’égalité de chaînes prédéfinis sont les suivants :The predefined string equality operators are:

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

Deux valeurs string sont considérées comme égales quand l’une des conditions suivantes est vraie :Two string values are considered equal when one of the following is true:

  • Les deux valeurs sont null.Both values are null.
  • Les deux valeurs sont des références non null aux instances de chaîne qui ont des longueurs identiques et des caractères identiques dans chaque position de caractère.Both values are non-null references to string instances that have identical lengths and identical characters in each character position.

Les opérateurs d’égalité de chaînes comparent les valeurs de chaîne plutôt que les références de chaîne.The string equality operators compare string values rather than string references. Lorsque deux instances de chaîne distinctes contiennent exactement la même séquence de caractères, les valeurs des chaînes sont égales, mais les références sont différentes.When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. Comme décrit dans opérateurs d’égalité de type référence, les opérateurs d’égalité de type référence peuvent être utilisés pour comparer des références de chaîne à la place de valeurs de chaîne.As described in Reference type equality operators, the reference type equality operators can be used to compare string references instead of string values.

Opérateurs d’égalité de déléguéDelegate equality operators

Chaque type délégué fournit implicitement les opérateurs de comparaison prédéfinis suivants :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);

Deux instances de délégué sont considérées comme étant égales comme suit :Two delegate instances are considered equal as follows:

  • Si l’une des instances de délégué est null, elles sont égales si et seulement si les deux sont null.If either of the delegate instances is null, they are equal if and only if both are null.
  • Si les délégués ont un type au moment de l’exécution différent, ils ne sont jamais égaux.If the delegates have different run-time type they are never equal.
  • Si les deux instances de délégué ont une liste d’appel (déclarations de délégué), ces instances sont égales si et seulement si leurs listes d’appel sont de la même longueur, et que chaque entrée de la liste d’appel de la première est égale (comme indiqué ci-dessous) au entrée, dans l’ordre, dans la liste d’appel de l’autre.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.

Les règles suivantes régissent l’égalité des entrées de la liste d’appel :The following rules govern the equality of invocation list entries:

  • Si deux entrées de liste d’appel font toutes deux référence à la même méthode statique, les entrées sont égales.If two invocation list entries both refer to the same static method then the entries are equal.
  • Si deux entrées de liste d’appel font toutes deux référence à la même méthode non statique sur le même objet cible (tel que défini par les opérateurs d’égalité de référence), les entrées sont égales.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.
  • Les entrées de la liste d’invocation générées à partir de l’évaluation de anonymous_method_expressionou lambda_expressions sémantiquement identiques avec le même ensemble (éventuellement vide) d’instances de variable externe capturée sont autorisées (mais pas obligatoires). valeur.Invocation list entries produced from evaluation of semantically identical anonymous_method_expressions or lambda_expressions with the same (possibly empty) set of captured outer variable instances are permitted (but not required) to be equal.

Opérateurs d’égalité et nullEquality operators and null

Les opérateurs == et != permettent à un opérande d’être une valeur d’un type Nullable et l’autre est le littéral null, même si aucun opérateur prédéfini ou défini par l’utilisateur (sous forme non levée) n’existe pour l’opération.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.

Pour une opération de l’une des formesFor an operation of one of the forms

x == null
null == x
x != null
null != x

x est une expression d’un type Nullable, si la résolution de surcharge d’opérateur (résolution de surcharge d’opérateur binaire) ne parvient pas à trouver un opérateur applicable, le résultat est à la place calculé à partir de la propriété HasValue de 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. Plus précisément, les deux premières formes sont converties en !x.HasValue, et les deux dernières sont traduites en x.HasValue.Specifically, the first two forms are translated into !x.HasValue, and last two forms are translated into x.HasValue.

Opérateur isThe is operator

L’opérateur is est utilisé pour vérifier dynamiquement si le type d’exécution d’un objet est compatible avec un type donné.The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. Le résultat de l’opération E is T, où E est une expression et T est un type, est une valeur booléenne indiquant si E peut être converti en type T par une conversion de référence, une conversion boxing ou une conversion unboxing.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. L’opération est évaluée comme suit, après que les arguments de type ont été substitués à tous les paramètres de type :The operation is evaluated as follows, after type arguments have been substituted for all type parameters:

  • Si E est une fonction anonyme, une erreur se produit au moment de la compilationIf E is an anonymous function, a compile-time error occurs
  • Si E est un groupe de méthodes ou le littéral null, si le type de E est un type référence ou un type Nullable et que la valeur de E est null, le résultat est 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.
  • Dans le cas contraire, laissez D représenter le type dynamique de E comme suit :Otherwise, let D represent the dynamic type of E as follows:
    • Si le type de E est un type référence, D est le type au moment de l’exécution de la référence de l’instance par E.If the type of E is a reference type, D is the run-time type of the instance reference by E.
    • Si le type de E est un type Nullable, D est le type sous-jacent de ce type Nullable.If the type of E is a nullable type, D is the underlying type of that nullable type.
    • Si le type de E est un type valeur n’acceptant pas les valeurs NULL, D est le type de E.If the type of E is a non-nullable value type, D is the type of E.
  • Le résultat de l’opération dépend de D et T, comme suit :The result of the operation depends on D and T as follows:
    • Si T est un type référence, le résultat est true si D et T sont du même type, si D est un type référence et qu’une conversion de référence implicite de D en T existe, ou si D est un type valeur et une conversion boxing de D à T existe.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.
    • Si T est un type Nullable, le résultat est true si D est le type sous-jacent de T.If T is a nullable type, the result is true if D is the underlying type of T.
    • Si T est un type valeur n’acceptant pas les valeurs NULL, le résultat est true si D et T sont du même type.If T is a non-nullable value type, the result is true if D and T are the same type.
    • Dans le cas contraire, le résultat est false.Otherwise, the result is false.

Notez que les conversions définies par l’utilisateur ne sont pas prises en compte par l’opérateur is.Note that user defined conversions, are not considered by the is operator.

Opérateur asThe as operator

L’opérateur as est utilisé pour convertir explicitement une valeur en un type référence ou un type Nullable donné.The as operator is used to explicitly convert a value to a given reference type or nullable type. Contrairement à une expression de cast (expressions de cast), l’opérateur as ne lève jamais d’exception.Unlike a cast expression (Cast expressions), the as operator never throws an exception. Au lieu de cela, si la conversion indiquée n’est pas possible, la valeur obtenue est null.Instead, if the indicated conversion is not possible, the resulting value is null.

Dans une opération de la forme E as T, E doit être une expression et T doit être un type référence, un paramètre de type connu comme étant un type référence ou un type Nullable.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. En outre, au moins l’une des conditions suivantes doit être vraie, sinon une erreur de compilation se produit :Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:

Si le type au moment de la compilation de E n’est pas dynamic, l’opération E as T produit le même résultat queIf 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

sauf que E n’est évalué qu’une seule fois.except that E is only evaluated once. Le compilateur peut être supposé optimiser E as T pour exécuter au plus un contrôle de type dynamique au lieu des deux contrôles de type dynamique qui sont implicites dans le cadre de l’expansion ci-dessus.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.

Si le type au moment de la compilation de E est dynamic, contrairement à l’opérateur de cast, l’opérateur as n’est pas lié dynamiquement (liaison dynamique).If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound (Dynamic binding). Par conséquent, dans ce cas, le développement est le suivant :Therefore the expansion in this case is:

E is T ? (T)(object)(E) : (T)null

Notez que certaines conversions, telles que les conversions définies par l’utilisateur, ne sont pas possibles avec l’opérateur as et doivent plutôt être effectuées à l’aide d’expressions de cast.Note that some conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.

Dans l’exempleIn 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 
    }
}

le paramètre de type T de G est connu comme étant un type référence, car il a la contrainte de classe.the type parameter T of G is known to be a reference type, because it has the class constraint. Toutefois, le paramètre de type U de H n’est pas ; par conséquent, l’utilisation de l’opérateur as dans H n’est pas autorisée.The type parameter U of H is not however; hence the use of the as operator in H is disallowed.

Opérateurs logiquesLogical operators

Les opérateurs &, ^ et | sont appelés opérateurs logiques.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
    ;

Si un opérande d’un opérateur logique a le type au moment de la compilation dynamic, l’expression est liée dynamiquement (liaison dynamique).If an operand of a logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Dans ce cas, le type au moment de la compilation de l’expression est dynamic, et la résolution décrite ci-dessous a lieu au moment de l’exécution en utilisant le type d’exécution des opérandes qui ont le type au moment de la compilation 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.

Pour une opération de la forme x op y, où op est l’un des opérateurs logiques, la résolution de surcharge (résolution de surcharge d’opérateur binaire) est appliquée pour sélectionner une implémentation d’opérateur spécifique.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. Les opérandes sont convertis en types de paramètre de l’opérateur sélectionné, et le type du résultat est le type de retour de l’opérateur.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.

Les opérateurs logiques prédéfinis sont décrits dans les sections suivantes.The predefined logical operators are described in the following sections.

Opérateurs logiques IntegerInteger logical operators

Les opérateurs logiques d’entiers prédéfinis sont les suivants :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);

L’opérateur & calcule le @no__t logique au niveau du bit-1 des deux opérandes, l’opérateur | calcule le @no__t logique au niveau du bit-3 des deux opérandes, et l’opérateur ^ calcule le @no__t exclusif logique au niveau du bit-5 des deux opérandes.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. Aucun dépassement de capacité n’est possible à partir de ces opérations.No overflows are possible from these operations.

Opérateurs logiques d’énumérationEnumeration logical operators

Chaque type d’énumération E fournit implicitement les opérateurs logiques prédéfinis suivants :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);

Le résultat de l’évaluation de x op y, où x et y sont des expressions d’un type énumération E avec un type sous-jacent U, et op est l’un des opérateurs logiques, est exactement le même que l’évaluation de (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). En d’autres termes, les opérateurs logiques de type énumération effectuent simplement l’opération logique sur le type sous-jacent des deux opérandes.In other words, the enumeration type logical operators simply perform the logical operation on the underlying type of the two operands.

Opérateurs logiques booléensBoolean logical operators

Les opérateurs logiques booléens prédéfinis sont les suivants :The predefined boolean logical operators are:

bool operator &(bool x, bool y);
bool operator |(bool x, bool y);
bool operator ^(bool x, bool y);

Le résultat de x & y est true si x et y sont true.The result of x & y is true if both x and y are true. Sinon, le résultat est false.Otherwise, the result is false.

Le résultat de x | y est true si x ou y est true.The result of x | y is true if either x or y is true. Sinon, le résultat est false.Otherwise, the result is false.

Le résultat de x ^ y est true si x est true et y est false, ou x est false et y est true.The result of x ^ y is true if x is true and y is false, or x is false and y is true. Sinon, le résultat est false.Otherwise, the result is false. Quand les opérandes sont de type bool, l’opérateur ^ calcule le même résultat que l’opérateur !=.When the operands are of type bool, the ^ operator computes the same result as the != operator.

Opérateurs logiques booléens NullableNullable boolean logical operators

Le type booléen Nullable bool? peut représenter trois valeurs, true, false et null, et est conceptuellement similaire au type à trois valeurs utilisé pour les expressions booléennes dans SQL.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. Pour garantir que les résultats produits par les opérateurs & et | pour les opérandes bool? sont cohérents avec la logique à trois valeurs de SQL, les opérateurs prédéfinis suivants sont fournis :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);

Le tableau suivant répertorie les résultats produits par ces opérateurs pour toutes les combinaisons des valeurs true, false et 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

Opérateurs logiques conditionnelsConditional logical operators

Les opérateurs && et || sont appelés opérateurs logiques conditionnels.The && and || operators are called the conditional logical operators. Elles sont également appelées opérateurs logiques de « court-circuit ».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
    ;

Les opérateurs && et || sont des versions conditionnelles des opérateurs & et | :The && and || operators are conditional versions of the & and | operators:

  • L’opération x && y correspond à l’opération x & y, sauf que y est évaluée uniquement si x n’est pas false.The operation x && y corresponds to the operation x & y, except that y is evaluated only if x is not false.
  • L’opération x || y correspond à l’opération x | y, sauf que y est évaluée uniquement si x n’est pas true.The operation x || y corresponds to the operation x | y, except that y is evaluated only if x is not true.

Si un opérande d’un opérateur logique conditionnel a le type au moment de la compilation dynamic, l’expression est liée dynamiquement (liaison dynamique).If an operand of a conditional logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Dans ce cas, le type au moment de la compilation de l’expression est dynamic, et la résolution décrite ci-dessous a lieu au moment de l’exécution en utilisant le type d’exécution des opérandes qui ont le type au moment de la compilation 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.

Une opération de la forme x && y ou x || y est traitée en appliquant la résolution de surcharge (résolution de surcharge d’opérateur binaire) comme si l’opération avait été écrite x & y ou 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. CliquezThen,

Il n’est pas possible de surcharger directement les opérateurs logiques conditionnels.It is not possible to directly overload the conditional logical operators. Toutefois, étant donné que les opérateurs logiques conditionnels sont évalués en termes d’opérateurs logiques standard, les surcharges des opérateurs logiques normaux sont, avec certaines restrictions, également considérées comme des surcharges des opérateurs logiques conditionnels.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. Cela est décrit plus en détail dans opérateurs logiques conditionnels définis par l’utilisateur.This is described further in User-defined conditional logical operators.

Opérateurs logiques conditionnels booléensBoolean conditional logical operators

Lorsque les opérandes de && ou || sont de type bool, ou lorsque les opérandes sont de types qui ne définissent pas un operator & ou operator | applicable, mais qui définissent les conversions implicites en bool, l’opération est traitée comme suit :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:

  • L’opération x && y est évaluée comme x ? y : false.The operation x && y is evaluated as x ? y : false. En d’autres termes, x est d’abord évalué et converti en type bool.In other words, x is first evaluated and converted to type bool. Ensuite, si x est true, y est évalué et converti en type bool, ce qui devient le résultat de l’opération.Then, if x is true, y is evaluated and converted to type bool, and this becomes the result of the operation. Dans le cas contraire, le résultat de l’opération est false.Otherwise, the result of the operation is false.
  • L’opération x || y est évaluée comme x ? true : y.The operation x || y is evaluated as x ? true : y. En d’autres termes, x est d’abord évalué et converti en type bool.In other words, x is first evaluated and converted to type bool. Ensuite, si x est true, le résultat de l’opération est true.Then, if x is true, the result of the operation is true. Dans le cas contraire, y est évalué et converti en type bool, ce qui devient le résultat de l’opération.Otherwise, y is evaluated and converted to type bool, and this becomes the result of the operation.

Opérateurs logiques conditionnels définis par l’utilisateurUser-defined conditional logical operators

Lorsque les opérandes de && ou || sont des types qui déclarent un operator & ou operator | défini par l’utilisateur, les deux conditions suivantes doivent être vraies, où T est le type dans lequel l’opérateur sélectionné est déclaré :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:

  • Le type de retour et le type de chaque paramètre de l’opérateur sélectionné doivent être T.The return type and the type of each parameter of the selected operator must be T. En d’autres termes, l’opérateur doit calculer le @no__t logique-0 ou le @no__t logique-1 de deux opérandes de type T, et doit retourner un résultat de type 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 doit contenir des déclarations de operator true et operator false.T must contain declarations of operator true and operator false.

Une erreur de liaison au moment de la liaison se produit si l’une de ces conditions n’est pas satisfaite.A binding-time error occurs if either of these requirements is not satisfied. Dans le cas contraire, l’opération && ou || est évaluée en combinant le operator true ou le operator false défini par l’utilisateur avec l’opérateur défini par l’utilisateur sélectionné :Otherwise, the && or || operation is evaluated by combining the user-defined operator true or operator false with the selected user-defined operator:

  • L’opération x && y est évaluée comme T.false(x) ? x : T.&(x, y), où T.false(x) est un appel du operator false déclaré dans T, et T.&(x, y) est un appel du operator & sélectionné.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 &. En d’autres termes, x est évaluée en premier et operator false est appelé sur le résultat pour déterminer si x est définitivement false.In other words, x is first evaluated and operator false is invoked on the result to determine if x is definitely false. Ensuite, si x est défini sur false, le résultat de l’opération est la valeur précédemment calculée pour x.Then, if x is definitely false, the result of the operation is the value previously computed for x. Dans le cas contraire, y est évaluée et le @no__t sélectionné-1 est appelé sur la valeur précédemment calculée pour x et la valeur calculée pour y pour produire le résultat de l’opération.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.
  • L’opération x || y est évaluée comme T.true(x) ? x : T.|(x, y), où T.true(x) est un appel du operator true déclaré dans T, et T.|(x,y) est un appel du operator| sélectionné.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|. En d’autres termes, x est évaluée pour la première fois et operator true est appelé sur le résultat pour déterminer si x est absolument true.In other words, x is first evaluated and operator true is invoked on the result to determine if x is definitely true. Ensuite, si x est défini sur true, le résultat de l’opération est la valeur précédemment calculée pour x.Then, if x is definitely true, the result of the operation is the value previously computed for x. Dans le cas contraire, y est évaluée et le @no__t sélectionné-1 est appelé sur la valeur précédemment calculée pour x et la valeur calculée pour y pour produire le résultat de l’opération.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.

Dans l’une ou l’autre de ces opérations, l’expression donnée par x est évaluée une seule fois, et l’expression donnée par y n’est pas évaluée ou évaluée une seule fois.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.

Pour obtenir un exemple de type qui implémente operator true et operator false, consultez Database Boolean type.For an example of a type that implements operator true and operator false, see Database boolean type.

Opérateur de fusion NullThe null coalescing operator

L’opérateur ?? est appelé opérateur de fusion Null.The ?? operator is called the null coalescing operator.

null_coalescing_expression
    : conditional_or_expression
    | conditional_or_expression '??' null_coalescing_expression
    ;

Une expression de fusion Null de la forme a ?? b requiert que a soit d’un type Nullable ou d’un type référence.A null coalescing expression of the form a ?? b requires a to be of a nullable type or reference type. Si a n’est pas null, le résultat de a ?? b est a ; dans le cas contraire, le résultat est b.If a is non-null, the result of a ?? b is a; otherwise, the result is b. L’opération évalue b uniquement si a a la valeur null.The operation evaluates b only if a is null.

L’opérateur de fusion Null est associatif à droite, ce qui signifie que les opérations sont regroupées de droite à gauche.The null coalescing operator is right-associative, meaning that operations are grouped from right to left. Par exemple, une expression de la forme a ?? b ?? c est évaluée comme a ?? (b ?? c).For example, an expression of the form a ?? b ?? c is evaluated as a ?? (b ?? c). En général, une expression de la forme E1 ?? E2 ?? ... ?? En retourne le premier des opérandes qui n’est pas null, ou null si tous les opérandes ont la valeur null.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.

Le type de l’expression a ?? b dépend des conversions implicites disponibles sur les opérandes.The type of the expression a ?? b depends on which implicit conversions are available on the operands. Par ordre de préférence, le type de a ?? b est A0, A ou B, où A est le type de a (à condition que a ait un type), B est le type de b (à condition que b ait un type) , et 0 est le type sous-jacent de 1 si 2 est un type Nullable, ou 3 dans le cas contraire.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. Plus précisément, a ?? b est traité comme suit :Specifically, a ?? b is processed as follows:

  • Si A existe et qu’il ne s’agit pas d’un type Nullable ou d’un type référence, une erreur de compilation se produit.If A exists and is not a nullable type or a reference type, a compile-time error occurs.
  • Si b est une expression dynamique, le type de résultat est dynamic.If b is a dynamic expression, the result type is dynamic. Au moment de l’exécution, a est évalué pour la première fois.At run-time, a is first evaluated. Si a n’est pas null, a est converti en dynamique, ce qui devient le résultat.If a is not null, a is converted to dynamic, and this becomes the result. Dans le cas contraire, b est évaluée, ce qui devient le résultat.Otherwise, b is evaluated, and this becomes the result.
  • Sinon, si A existe et qu’il s’agit d’un type Nullable et qu’il existe une conversion implicite de b en A0, le type de résultat est A0.Otherwise, if A exists and is a nullable type and an implicit conversion exists from b to A0, the result type is A0. Au moment de l’exécution, a est évalué pour la première fois.At run-time, a is first evaluated. Si a n’est pas null, a est désencapsulée dans le type A0, ce qui devient le résultat.If a is not null, a is unwrapped to type A0, and this becomes the result. Dans le cas contraire, b est évalué et converti en type A0, ce qui devient le résultat.Otherwise, b is evaluated and converted to type A0, and this becomes the result.
  • Sinon, si A existe et qu’il existe une conversion implicite de b en A, le type de résultat est A.Otherwise, if A exists and an implicit conversion exists from b to A, the result type is A. Au moment de l’exécution, a est évalué pour la première fois.At run-time, a is first evaluated. Si a n’est pas null, a devient le résultat.If a is not null, a becomes the result. Dans le cas contraire, b est évalué et converti en type A, ce qui devient le résultat.Otherwise, b is evaluated and converted to type A, and this becomes the result.
  • Sinon, si b a un type B et qu’il existe une conversion implicite de a en B, le type de résultat est B.Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. Au moment de l’exécution, a est évalué pour la première fois.At run-time, a is first evaluated. Si a n’est pas null, a est désencapsulée dans le type A0 (si A existe et est Nullable) et converti en type B, et cela devient le résultat.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. Dans le cas contraire, b est évalué et devient le résultat.Otherwise, b is evaluated and becomes the result.
  • Dans le cas contraire, a et b sont incompatibles, et une erreur de compilation se produit.Otherwise, a and b are incompatible, and a compile-time error occurs.

Opérateur conditionnelConditional operator

L’opérateur ?: est appelé opérateur conditionnel.The ?: operator is called the conditional operator. Il est parfois également appelé opérateur ternaire.It is at times also called the ternary operator.

conditional_expression
    : null_coalescing_expression
    | null_coalescing_expression '?' expression ':' expression
    ;

Une expression conditionnelle de la forme b ? x : y évalue d’abord la condition b.A conditional expression of the form b ? x : y first evaluates the condition b. Ensuite, si b est true, x est évaluée et devient le résultat de l’opération.Then, if b is true, x is evaluated and becomes the result of the operation. Dans le cas contraire, y est évalué et devient le résultat de l’opération.Otherwise, y is evaluated and becomes the result of the operation. Une expression conditionnelle n’évalue jamais à la fois x et y.A conditional expression never evaluates both x and y.

L’opérateur conditionnel est associatif à droite, ce qui signifie que les opérations sont regroupées de droite à gauche.The conditional operator is right-associative, meaning that operations are grouped from right to left. Par exemple, une expression de la forme a ? b : c ? d : e est évaluée comme 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).

Le premier opérande de l’opérateur ?: doit être une expression qui peut être implicitement convertie en bool, ou une expression d’un type qui implémente 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. Si aucune de ces exigences n’est satisfaite, une erreur de compilation se produit.If neither of these requirements is satisfied, a compile-time error occurs.

Le deuxième et le troisième opérandes, x et y, de l’opérateur ?: contrôlent le type de l’expression conditionnelle.The second and third operands, x and y, of the ?: operator control the type of the conditional expression.

  • Si x a le type X et y a le type Y, puisIf x has type X and y has type Y then
    • Si une conversion implicite (conversions implicites) existe entre X et Y, mais pas de Y à X, Y est le type de l’expression conditionnelle.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.
    • Si une conversion implicite (conversions implicites) existe entre Y et X, mais pas de X à Y, X est le type de l’expression conditionnelle.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.
    • Dans le cas contraire, aucun type d’expression ne peut être déterminé et une erreur de compilation se produit.Otherwise, no expression type can be determined, and a compile-time error occurs.
  • Si une seule des x et y a un type, et que x et y, de sont implicitement convertibles en ce type, alors il s’agit du type de l’expression conditionnelle.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.
  • Dans le cas contraire, aucun type d’expression ne peut être déterminé et une erreur de compilation se produit.Otherwise, no expression type can be determined, and a compile-time error occurs.

Le traitement au moment de l’exécution d’une expression conditionnelle de la forme b ? x : y comprend les étapes suivantes :The run-time processing of a conditional expression of the form b ? x : y consists of the following steps:

  • Tout d’abord, b est évaluée et la valeur bool de b est déterminée :First, b is evaluated, and the bool value of b is determined:
    • Si une conversion implicite du type de b en bool existe, cette conversion implicite est effectuée pour produire une valeur bool.If an implicit conversion from the type of b to bool exists, then this implicit conversion is performed to produce a bool value.
    • Dans le cas contraire, le operator true défini par le type de b est appelé pour produire une valeur bool.Otherwise, the operator true defined by the type of b is invoked to produce a bool value.
  • Si la valeur bool produite par l’étape ci-dessus est true, x est évalué et converti en type de l’expression conditionnelle, ce qui devient le résultat de l’expression conditionnelle.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.
  • Dans le cas contraire, y est évalué et converti en type de l’expression conditionnelle, ce qui devient le résultat de l’expression conditionnelle.Otherwise, y is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.

Expressions de fonctions anonymesAnonymous function expressions

Une fonction anonyme est une expression qui représente une définition de méthode « in-line ».An anonymous function is an expression that represents an "in-line" method definition. Une fonction anonyme n’a pas de valeur ou de type dans et de elle-même, mais elle peut être convertie en un délégué compatible ou un type d’arborescence d’expression.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. L’évaluation d’une conversion de fonction anonyme dépend du type de cible de la conversion : S’il s’agit d’un type délégué, la conversion prend la valeur d’une valeur de délégué référençant la méthode définie par la fonction anonyme.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. S’il s’agit d’un type d’arborescence d’expression, la conversion prend la valeur d’une arborescence d’expressions qui représente la structure de la méthode sous la forme d’une structure d’objet.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.

Pour des raisons historiques, il existe deux versions syntaxiques des fonctions anonymes, à savoir lambda_expressions et anonymous_method_expression.For historical reasons there are two syntactic flavors of anonymous functions, namely lambda_expressions and anonymous_method_expressions. Pour presque tous les besoins, les lambda_expressionsont plus concises et plus expressifs que les anonymous_method_expression, qui restent dans le langage à des fins de compatibilité descendante.For almost all purposes, lambda_expressions are more concise and expressive than anonymous_method_expressions, 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
    ;

L’opérateur => a la même priorité que l’assignation (=) et est associatif à droite.The => operator has the same precedence as assignment (=) and is right-associative.

Une fonction anonyme avec le modificateur async est une fonction Async et suit les règles décrites dans itérateurs.An anonymous function with the async modifier is an async function and follows the rules described in Iterators.

Les paramètres d’une fonction anonyme sous la forme d’un lambda_expression peuvent être explicitement ou implicitement typés.The parameters of an anonymous function in the form of a lambda_expression can be explicitly or implicitly typed. Dans une liste de paramètres typés explicitement, le type de chaque paramètre est défini explicitement.In an explicitly typed parameter list, the type of each parameter is explicitly stated. Dans une liste de paramètres typée implicitement, les types des paramètres sont déduits du contexte dans lequel la fonction anonyme se produit, en particulier lorsque la fonction anonyme est convertie en un type délégué compatible ou un type d’arborescence d’expression, ce type fournit types de paramètres (conversions de fonctions anonymes).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).

Dans une fonction anonyme avec un seul paramètre typé implicitement, les parenthèses peuvent être omises dans la liste de paramètres.In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. En d’autres termes, une fonction anonyme de la formeIn other words, an anonymous function of the form

( param ) => expr

peut être abrégé encan be abbreviated to

param => expr

La liste des paramètres d’une fonction anonyme sous la forme d’un anonymous_method_expression est facultative.The parameter list of an anonymous function in the form of an anonymous_method_expression is optional. Si elles sont spécifiées, les paramètres doivent être explicitement typés.If given, the parameters must be explicitly typed. Si ce n’est pas le cas, la fonction anonyme est convertible en un délégué avec une liste de paramètres qui ne contient pas de paramètres out.If not, the anonymous function is convertible to a delegate with any parameter list not containing out parameters.

Un corps de bloc d’une fonction anonyme est accessible (points de terminaison et accessibilité) sauf si la fonction anonyme se produit à l’intérieur d’une instruction inaccessible.A block body of an anonymous function is reachable (End points and reachability) unless the anonymous function occurs inside an unreachable statement.

Voici quelques exemples de fonctions anonymes :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

Le comportement de lambda_expressions et anonymous_method_expressions est le même, à l’exception des points suivants :The behavior of lambda_expressions and anonymous_method_expressions is the same except for the following points:

  • anonymous_method_expressions autorise l’omission complète de la liste de paramètres, ce qui donne convertibilité aux types délégués d’une liste de paramètres de valeur.anonymous_method_expressions permit the parameter list to be omitted entirely, yielding convertibility to delegate types of any list of value parameters.
  • les lambda_expressions autorisent l’omission et la déduction des types de paramètres, tandis que lestypes de paramètres doivent être explicitement déclarés.lambda_expressions permit parameter types to be omitted and inferred whereas anonymous_method_expressions require parameter types to be explicitly stated.
  • Le corps d’un lambda_expression peut être une expression ou un bloc d’instructions, tandis que le corps d’un anonymous_method_expression doit être un bloc d’instructions.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.
  • Seuls les lambda_expressions ont des conversions en types d’arborescence d’expression compatibles (types d’arborescence d’expression).Only lambda_expressions have conversions to compatible expression tree types (Expression tree types).

Signatures de fonctions anonymesAnonymous function signatures

Le anonymous_function_signature facultatif d’une fonction anonyme définit les noms et éventuellement les types des paramètres formels pour la fonction anonyme.The optional anonymous_function_signature of an anonymous function defines the names and optionally the types of the formal parameters for the anonymous function. La portée des paramètres de la fonction anonyme est anonymous_function_body.The scope of the parameters of the anonymous function is the anonymous_function_body. (Étendues) Avec la liste de paramètres (si elle est donnée), le corps de la méthode anonyme constitue un espace de déclaration (déclarations).(Scopes) Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space (Declarations). Il s’agit donc d’une erreur au moment de la compilation pour le nom d’un paramètre de la fonction anonyme qui correspond au nom d’une variable locale, d’une constante locale ou d’un paramètre dont l’étendue comprend anonymous_method_expression ou lambda_expression.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.

Si une fonction anonyme a un explicit_anonymous_function_signature, l’ensemble de types de délégués compatibles et de types d’arborescence d’expression est limité à ceux qui ont les mêmes types de paramètres et modificateurs dans le même ordre.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. Contrairement aux conversions de groupe de méthodes (conversions de groupe de méthodes), la contre-variance des types de paramètre de fonction anonyme n’est pas prise en charge.In contrast to method group conversions (Method group conversions), contra-variance of anonymous function parameter types is not supported. Si une fonction anonyme n’a pas de anonymous_function_signature, l’ensemble de types de délégués compatibles et de types d’arborescence d’expression est limité à ceux qui n’ont pas de paramètres 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.

Notez qu’un anonymous_function_signature ne peut pas inclure des attributs ou un tableau de paramètres.Note that an anonymous_function_signature cannot include attributes or a parameter array. Toutefois, un anonymous_function_signature peut être compatible avec un type délégué dont la liste de paramètres contient un tableau de paramètres.Nevertheless, an anonymous_function_signature may be compatible with a delegate type whose parameter list contains a parameter array.

Notez également que la conversion en un type d’arborescence d’expression, même si elle est compatible, peut encore échouer au moment de la compilation (types d’arborescence d’expression).Note also that conversion to an expression tree type, even if compatible, may still fail at compile-time (Expression tree types).

Corps des fonctions anonymesAnonymous function bodies

Le corps (expression ou bloc) d’une fonction anonyme est soumis aux règles suivantes :The body (expression or block) of an anonymous function is subject to the following rules:

  • Si la fonction anonyme comprend une signature, les paramètres spécifiés dans la signature sont disponibles dans le corps.If the anonymous function includes a signature, the parameters specified in the signature are available in the body. Si la fonction anonyme n’a pas de signature, elle peut être convertie en type délégué ou type d’expression ayant des paramètres (conversions de fonctions anonymes), mais les paramètres ne sont pas accessibles dans le corps.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.
  • À l’exception des paramètres ref ou out spécifiés dans la signature (le cas échéant) de la fonction anonyme englobante la plus proche, il s’agit d’une erreur au moment de la compilation pour que le corps accède à un paramètre ref ou out.Except 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.
  • Lorsque le type de this est un type struct, il s’agit d’une erreur au moment de la compilation pour que le corps accède à this.When the type of this is a struct type, it is a compile-time error for the body to access this. Cela est vrai, que l’accès soit explicite (par exemple, this.x) ou implicite (comme dans xx est un membre d’instance du struct).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). Cette règle interdit simplement cet accès et n’affecte pas si la recherche de membres est un membre du struct.This rule simply prohibits such access and does not affect whether member lookup results in a member of the struct.
  • Le corps a accès aux variables externes (variables externes) de la fonction anonyme.The body has access to the outer variables (Outer variables) of the anonymous function. L’accès à une variable externe fait référence à l’instance de la variable qui est active au moment de l’évaluation de lambda_expression ou anonymous_method_expression (évaluation des expressions de fonction anonymes).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).
  • Il s’agit d’une erreur au moment de la compilation pour que le corps contienne une instruction goto, une instruction break ou une instruction continue dont la cible est en dehors du corps ou dans le corps d’une fonction anonyme contenue.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.
  • Une instruction return dans le corps retourne le contrôle à partir d’un appel de la fonction anonyme englobante la plus proche, et non du membre de la fonction englobante.A return statement in the body returns control from an invocation of the nearest enclosing anonymous function, not from the enclosing function member. Une expression spécifiée dans une instruction return doit être implicitement convertible en type de retour du type délégué ou du type d’arborescence d’expression vers lequel le lambda_expression ou le anonymous_method_expression le plus proche est converti ( Conversions de fonctions anonymes).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).

Elle n’est pas explicitement spécifiée, qu’il existe un moyen d’exécuter le bloc d’une fonction anonyme autre que par le biais de l’évaluation et de l’appel de lambda_expression ou 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. En particulier, le compilateur peut choisir d’implémenter une fonction anonyme en synthétisant une ou plusieurs méthodes ou types nommés.In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types. Les noms de ces éléments synthétisés doivent être d’une forme réservée à l’utilisation du compilateur.The names of any such synthesized elements must be of a form reserved for compiler use.

Résolution de surcharge et fonctions anonymesOverload resolution and anonymous functions

Les fonctions anonymes dans une liste d’arguments participent à l’inférence de type et à la résolution de surcharge.Anonymous functions in an argument list participate in type inference and overload resolution. Reportez-vous à l' inférence de type et à la résolution de surcharge pour les règles exactes.Please refer to Type inference and Overload resolution for the exact rules.

L’exemple suivant illustre l’effet des fonctions anonymes sur la résolution de surcharge.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;
    }
}

La classe ItemList<T> a deux méthodes Sum.The ItemList<T> class has two Sum methods. Chaque accepte un argument selector, qui extrait la valeur à additionner d’un élément de liste.Each takes a selector argument, which extracts the value to sum over from a list item. La valeur extraite peut être un int ou un double et la somme résultante est également une int ou une double.The extracted value can be either an int or a double and the resulting sum is likewise either an int or a double.

Les méthodes Sum peuvent par exemple être utilisées pour calculer des sommes à partir d’une liste de lignes de détails dans un ordre.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);
    ...
}

Lors du premier appel de orderDetails.Sum, les deux méthodes Sum sont applicables, car la fonction anonyme d => d. UnitCount est compatible avec Func<Detail,int> et 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>. Toutefois, la résolution de surcharge choisit la première méthode Sum, car la conversion en Func<Detail,int> est meilleure que la conversion en 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>.

Dans le deuxième appel de orderDetails.Sum, seule la deuxième méthode Sum est applicable, car la fonction anonyme d => d.UnitPrice * d.UnitCount produit une valeur de type 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. Par conséquent, la résolution de surcharge sélectionne la deuxième méthode Sum pour cet appel.Thus, overload resolution picks the second Sum method for that invocation.

Fonctions anonymes et liaison dynamiqueAnonymous functions and dynamic binding

Une fonction anonyme ne peut pas être un récepteur, un argument ou un opérande d’une opération liée dynamiquement.An anonymous function cannot be a receiver, argument or operand of a dynamically bound operation.

Variables externesOuter variables

Toute variable locale, paramètre de valeur ou tableau de paramètres dont la portée comprend lambda_expression ou anonymous_method_expression est appelée une variable externe de la fonction anonyme.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. Dans une fonction membre d’instance d’une classe, la valeur this est considérée comme un paramètre de valeur et est une variable externe de toute fonction anonyme contenue dans la fonction membre.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.

Variables externes capturéesCaptured outer variables

Lorsqu’une variable externe est référencée par une fonction anonyme, la variable externe est dite capturée par la fonction anonyme.When an outer variable is referenced by an anonymous function, the outer variable is said to have been captured by the anonymous function. En règle générale, la durée de vie d’une variable locale est limitée à l’exécution du bloc ou de l’instruction à laquelle elle est associée (variables locales).Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated (Local variables). Toutefois, la durée de vie d’une variable externe capturée est étendue au moins jusqu’à ce que le délégué ou l’arborescence d’expressions créé à partir de la fonction anonyme devienne éligible pour garbage collection.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.

Dans l’exempleIn 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());
    }
}

la variable locale x est capturée par la fonction anonyme, et la durée de vie de x est étendue au moins jusqu’à ce que le délégué retourné à partir de F devienne éligible pour garbage collection (ce qui ne se produit pas jusqu’à la fin du programme).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). Étant donné que chaque appel de la fonction anonyme opère sur la même instance de x, la sortie de l’exemple est :Since each invocation of the anonymous function operates on the same instance of x, the output of the example is:

1
2
3

Lorsqu’une variable locale ou un paramètre de valeur est capturé par une fonction anonyme, la variable locale ou le paramètre n’est plus considéré comme une variable fixe (variables fixes et déplaçables), mais est considéré comme une variable déplaçable.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. Ainsi, tout code unsafe qui prend l’adresse d’une variable externe capturée doit d’abord utiliser l’instruction fixed pour corriger la variable.Thus any unsafe code that takes the address of a captured outer variable must first use the fixed statement to fix the variable.

Notez que contrairement à une variable non capturée, une variable locale capturée peut être exposée simultanément à plusieurs threads d’exécution.Note that unlike an uncaptured variable, a captured local variable can be simultaneously exposed to multiple threads of execution.

Instanciation de variables localesInstantiation of local variables

Une variable locale est considérée comme instanciée lorsque l’exécution entre dans l’étendue de la variable.A local variable is considered to be instantiated when execution enters the scope of the variable. Par exemple, lorsque la méthode suivante est appelée, la variable locale x est instanciée et initialisée trois fois, une fois pour chaque itération de la boucle.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;
        ...
    }
}

Toutefois, le déplacement de la déclaration de x en dehors de la boucle entraîne une instanciation unique de 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;
        ...
    }
}

Lorsqu’elles ne sont pas capturées, il n’existe aucun moyen d’observer exactement la fréquence à laquelle une variable locale est instanciée. étant donné que les durées de vie des instanciations sont disjointes, il est possible que chaque instanciation utilise simplement le même emplacement de stockage.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. Toutefois, lorsqu’une fonction anonyme capture une variable locale, les effets de l’instanciation deviennent évidents.However, when an anonymous function captures a local variable, the effects of instantiation become apparent.

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

génère cette sortie :produces the output:

1
3
5

Toutefois, lorsque la déclaration de x est déplacée en dehors de la boucle :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;
}

La sortie est la suivante :the output is:

5
5
5

Si une boucle for déclare une variable d’itération, cette variable est considérée comme déclarée en dehors de la boucle.If a for-loop declares an iteration variable, that variable itself is considered to be declared outside of the loop. Ainsi, si l’exemple est modifié pour capturer la variable d’itération elle-même :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;
}

une seule instance de la variable d’itération est capturée, ce qui génère la sortie :only one instance of the iteration variable is captured, which produces the output:

3
3
3

Il est possible que les délégués de fonction anonymes partagent des variables capturées, mais des instances distinctes d’autres.It is possible for anonymous function delegates to share some captured variables yet have separate instances of others. Par exemple, si F est remplacé parFor 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;
}

les trois délégués capturent la même instance de x, mais des instances distinctes de y, et la sortie est :the three delegates capture the same instance of x but separate instances of y, and the output is:

1 1
2 1
3 1

Des fonctions anonymes distinctes peuvent capturer la même instance d’une variable externe.Separate anonymous functions can capture the same instance of an outer variable. Dans l'exemple :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());
    }
}

les deux fonctions anonymes capturent la même instance de la variable locale x, et elles peuvent donc « communiquer » par le biais de cette variable.the two anonymous functions capture the same instance of the local variable x, and they can thus "communicate" through that variable. La sortie de l’exemple est la suivante :The output of the example is:

5
10

Évaluation des expressions de fonction anonymesEvaluation of anonymous function expressions

Une fonction anonyme F doit toujours être convertie en type délégué D ou en type d’arborescence d’expression E, soit directement, soit par le biais de l’exécution d’une expression de création de délégué new D(F).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). Cette conversion détermine le résultat de la fonction anonyme, comme décrit dans conversions de fonctions anonymes.This conversion determines the result of the anonymous function, as described in Anonymous function conversions.

Expressions de requêteQuery expressions

Les expressions de requête fournissent une syntaxe intégrée au langage pour les requêtes qui est semblable aux langages de requête relationnels et hiérarchiques tels que SQL et XQuery.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
    ;

Une expression de requête commence par une clause from et se termine par une clause select ou group.A query expression begins with a from clause and ends with either a select or group clause. La clause initiale from peut être suivie par zéro, une ou plusieurs clauses from, let, where, join ou orderby.The initial from clause can be followed by zero or more from, let, where, join or orderby clauses. Chaque clause from est un générateur qui introduit une variable de portée qui s’étend sur les éléments d’une séquence.Each from clause is a generator introducing a range variable which ranges over the elements of a sequence. Chaque clause let introduit une variable de portée représentant une valeur calculée au moyen de variables de plage précédentes.Each let clause introduces a range variable representing a value computed by means of previous range variables. Chaque clause where est un filtre qui exclut des éléments du résultat.Each where clause is a filter that excludes items from the result. Chaque clause join compare les clés spécifiées de la séquence source avec les clés d’une autre séquence, ce qui génère des paires correspondantes.Each join clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. Chaque clause orderby réorganise les éléments en fonction des critères spécifiés. La dernière clause select ou group spécifie la forme du résultat en termes de variables de plage.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. Enfin, une clause into peut être utilisée pour « épisser » des requêtes en traitant les résultats d’une requête sous la forme d’un générateur dans une requête suivante.Finally, an into clause can be used to "splice" queries by treating the results of one query as a generator in a subsequent query.

Ambiguïtés dans les expressions de requêteAmbiguities in query expressions

Les expressions de requête contiennent un certain nombre de « mots-clés contextuels », c’est-à-dire des identificateurs qui ont une signification particulière dans un contexte donné.Query expressions contain a number of "contextual keywords", i.e., identifiers that have special meaning in a given context. En particulier, il s’agit de from, where, join, on, equals, into, let, orderby, ascending, descending, 0, 1 et 2.Specifically these are from, where, join, on, equals, into, let, orderby, ascending, descending, select, group and by. Afin d’éviter les ambiguïtés dans les expressions de requête provoquées par l’utilisation mixte de ces identificateurs en tant que Mots clés ou noms simples, ces identificateurs sont considérés comme des mots clés lorsqu’ils se trouvent n’importe où dans une expression de requête.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.

À cet effet, une expression de requête est une expression qui commence par « from identifier » suivi d’un jeton, à l’exception de « ; », « = » ou « , ».For this purpose, a query expression is any expression that starts with "from identifier" followed by any token except ";", "=" or ",".

Pour pouvoir utiliser ces mots comme identificateurs dans une expression de requête, ils peuvent être précédés de « @ » (identificateurs).In order to use these words as identifiers within a query expression, they can be prefixed with "@" (Identifiers).

Traduction d’expression de requêteQuery expression translation

Le C# langage ne spécifie pas la sémantique d’exécution des expressions de requête.The C# language does not specify the execution semantics of query expressions. Au lieu de cela, les expressions de requête sont traduites en appels de méthodes qui adhèrent au modèle d’expression de requête (le modèle d’expression de requête).Rather, query expressions are translated into invocations of methods that adhere to the query expression pattern (The query expression pattern). Plus précisément, les expressions de requête sont traduites en appels de méthodes nommées Where, Select, SelectMany, Join, GroupJoin, OrderBy, OrderByDescending, ThenBy, ThenByDescending, GroupBy et 0. Ces méthodes sont supposées avoir des signatures et des types de résultats particuliers, comme décrit dans le modèle d’expression de requête.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. Ces méthodes peuvent être des méthodes d’instance de l’objet interrogé ou des méthodes d’extension qui sont externes à l’objet, et elles implémentent l’exécution réelle de la requête.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.

La traduction des expressions de requête en appels de méthode est un mappage syntaxique qui se produit avant l’exécution d’une quelconque liaison de type ou de surcharge.The translation from query expressions to method invocations is a syntactic mapping that occurs before any type binding or overload resolution has been performed. La syntaxe de la traduction est garantie, mais il n’est pas garanti que la génération de code est C# correcte.The translation is guaranteed to be syntactically correct, but it is not guaranteed to produce semantically correct C# code. À la suite de la traduction des expressions de requête, les appels de méthode résultants sont traités comme des appels de méthode normaux, ce qui peut à son tour dévoiler les erreurs, par exemple si les méthodes n’existent pas, si les arguments ont des types incorrects, ou si les méthodes sont génériques et l’inférence de type échoue.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.

Une expression de requête est traitée en appliquant à plusieurs reprises les traductions suivantes jusqu’à ce qu’aucune réduction supplémentaire ne soit possible.A query expression is processed by repeatedly applying the following translations until no further reductions are possible. Les traductions sont répertoriées dans l’ordre de l’application : chaque section suppose que les traductions dans les sections précédentes ont été effectuées de façon exhaustive, et une fois épuisées, une section n’est pas revisitée ultérieurement dans le traitement de la même expression de requête.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.

L’assignation à des variables de portée n’est pas autorisée dans les expressions de requête.Assignment to range variables is not allowed in query expressions. Toutefois, C# une implémentation est autorisée à ne pas toujours appliquer cette restriction, car cela peut parfois ne pas être possible avec le schéma de traduction syntaxique présenté ici.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.

Certaines traductions injectent des variables de portée avec des identificateurs transparents dénotés par *.Certain translations inject range variables with transparent identifiers denoted by *. Les propriétés spéciales des identificateurs transparents sont décrites plus en détail dans identificateurs transparents.The special properties of transparent identifiers are discussed further in Transparent identifiers.

Clauses SELECT et GroupBy avec continuationsSelect and groupby clauses with continuations

Expression de requête avec une continuationA query expression with a continuation

from ... into x ...

est traduit enis translated into

from x in ( from ... ) ...

Les traductions des sections suivantes supposent que les requêtes n’ont aucune continuation into.The translations in the following sections assume that queries have no into continuations.

L’exempleThe example

from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }

est traduit enis translated into

from g in
    from c in customers
    group c by c.Country
select new { Country = g.Key, CustCount = g.Count() }

traduction finale de qui estthe final translation of which is

customers.
GroupBy(c => c.Country).
Select(g => new { Country = g.Key, CustCount = g.Count() })

Types de variable de portée expliciteExplicit range variable types

Une clause from qui spécifie explicitement un type de variable de portéeA from clause that explicitly specifies a range variable type

from T x in e

est traduit enis translated into

from x in ( e ) . Cast < T > ( )

Une clause join qui spécifie explicitement un type de variable de portéeA join clause that explicitly specifies a range variable type

join T x in e on k1 equals k2

est traduit enis translated into

join x in ( e ) . Cast < T > ( ) on k1 equals k2

Les traductions dans les sections suivantes supposent que les requêtes n’ont pas de types de variable de portée explicite.The translations in the following sections assume that queries have no explicit range variable types.

L’exempleThe example

from Customer c in customers
where c.City == "London"
select c

est traduit enis translated into

from c in customers.Cast<Customer>()
where c.City == "London"
select c

traduction finale de qui estthe final translation of which is

customers.
Cast<Customer>().
Where(c => c.City == "London")

Les types de variable de portée explicite sont utiles pour interroger des collections qui implémentent l’interface non générique IEnumerable, mais pas l’interface générique IEnumerable<T>.Explicit range variable types are useful for querying collections that implement the non-generic IEnumerable interface, but not the generic IEnumerable<T> interface. Dans l’exemple ci-dessus, ce serait le cas si customers était de type ArrayList.In the example above, this would be the case if customers were of type ArrayList.

Dégénérer des expressions de requêteDegenerate query expressions

Expression de requête de la formeA query expression of the form

from x in e select x

est traduit enis translated into

( e ) . Select ( x => x )

L’exempleThe example

from c in customers
select c

est traduit enis translated into

customers.Select(c => c)

Une expression de requête dégénérée est une expression qui sélectionne de façon triviale les éléments de la source.A degenerate query expression is one that trivially selects the elements of the source. Une phase ultérieure de la traduction supprime les requêtes dégénérées introduites par d’autres étapes de traduction en les remplaçant par leur source.A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. Toutefois, il est important de s’assurer que le résultat d’une expression de requête n’est jamais l’objet source lui-même, car cela révélerait le type et l’identité de la source au client de la requête.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. Par conséquent, cette étape protège les requêtes dégénérées écrites directement dans le code source en appelant explicitement Select sur la source.Therefore this step protects degenerate queries written directly in source code by explicitly calling Select on the source. Il s’agit ensuite des implémenteurs de Select et d’autres opérateurs de requête pour garantir que ces méthodes ne retournent jamais l’objet source lui-même.It is then up to the implementers of Select and other query operators to ensure that these methods never return the source object itself.

Clauses from, Let, Where, Join et OrderByFrom, let, where, join and orderby clauses

Expression de requête avec une deuxième clause from suivie d’une clause selectA query expression with a second from clause followed by a select clause

from x1 in e1
from x2 in e2
select v

est traduit enis translated into

( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )

Une expression de requête avec une deuxième clause from suivie d’une autre chose qu’une clause select :A query expression with a second from clause followed by something other than a select clause:

from x1 in e1
from x2 in e2
...

est traduit enis translated into

from * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } )
...

Expression de requête avec une clause letA query expression with a let clause

from x in e
let y = f
...

est traduit enis translated into

from * in ( e ) . Select ( x => new { x , y = f } )
...

Expression de requête avec une clause whereA query expression with a where clause

from x in e
where f
...

est traduit enis translated into

from x in ( e ) . Where ( x => f )
...

Expression de requête avec une clause join sans into suivie d’une clause selectA 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

est traduit enis translated into

( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => v )

Expression de requête avec une clause join sans into suivi d’un autre nom que la clause selectA 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
...

est traduit enis translated into

from * in ( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })
...

Expression de requête avec une clause join avec une into suivie d’une clause selectA 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

est traduit enis translated into

( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => v )

Expression de requête avec une clause join avec un into suivi d’un autre nom que la clause selectA 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
...

est traduit enis translated into

from * in ( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => new { x1 , g })
...

Expression de requête avec une clause orderbyA query expression with an orderby clause

from x in e
orderby k1 , k2 , ..., kn
...

est traduit enis translated into

from x in ( e ) . 
OrderBy ( x => k1 ) . 
ThenBy ( x => k2 ) .
... .
ThenBy ( x => kn )
...

Si une clause de classement spécifie un indicateur de direction descending, un appel de OrderByDescending ou ThenByDescending est produit à la place.If an ordering clause specifies a descending direction indicator, an invocation of OrderByDescending or ThenByDescending is produced instead.

Les traductions suivantes supposent qu’il n’existe pas de clauses let, where, join ou orderby, et pas plus que la seule clause initiale from dans chaque expression de requête.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.

L’exempleThe example

from c in customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total }

est traduit enis translated into

customers.
SelectMany(c => c.Orders,
     (c,o) => new { c.Name, o.OrderID, o.Total }
)

L’exempleThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }

est traduit enis 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 }

traduction finale de qui estthe 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 })

x est un identificateur généré par le compilateur qui est autrement invisible et inaccessible.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

L’exempleThe example

from o in orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t }

est traduit enis 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 }

traduction finale de qui estthe 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 })

x est un identificateur généré par le compilateur qui est autrement invisible et inaccessible.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

L’exempleThe example

from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }

est traduit enis translated into

customers.Join(orders, c => c.CustomerID, o => o.CustomerID,
    (c, o) => new { c.Name, o.OrderDate, o.Total })

L’exempleThe 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 }

est traduit enis 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 }

traduction finale de qui estthe 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)

x et y sont des identificateurs générés par le compilateur qui, sinon, sont inaccessibles et inaccessibles.where x and y are compiler generated identifiers that are otherwise invisible and inaccessible.

L’exempleThe example

from o in orders
orderby o.Customer.Name, o.Total descending
select o

a la traduction finalehas the final translation

orders.
OrderBy(o => o.Customer.Name).
ThenByDescending(o => o.Total)

Clauses SELECTSelect clauses

Expression de requête de la formeA query expression of the form

from x in e select v

est traduit enis translated into

( e ) . Select ( x => v )

sauf lorsque v est l’identificateur x, la traduction est simplementexcept when v is the identifier x, the translation is simply

( e )

Exemple :For example

from c in customers.Where(c => c.City == "London")
select c

est simplement traduit enis simply translated into

customers.Where(c => c.City == "London")

Clauses GROUPBYGroupby clauses

Expression de requête de la formeA query expression of the form

from x in e group v by k

est traduit enis translated into

( e ) . GroupBy ( x => k , x => v )

sauf lorsque v est l’identificateur x, la traduction estexcept when v is the identifier x, the translation is

( e ) . GroupBy ( x => k )

L’exempleThe example

from c in customers
group c.Name by c.Country

est traduit enis translated into

customers.
GroupBy(c => c.Country, c => c.Name)

Identificateurs transparentsTransparent identifiers

Certaines traductions injectent des variables de portée avec des identificateurs transparents dénotés par *.Certain translations inject range variables with transparent identifiers denoted by *. Les identificateurs transparents ne sont pas une fonctionnalité de langage appropriée. ils existent uniquement comme étape intermédiaire dans le processus de traduction d’expression de requête.Transparent identifiers are not a proper language feature; they exist only as an intermediate step in the query expression translation process.

Quand une traduction de requête injecte un identificateur transparent, d’autres étapes de traduction propagent l’identificateur transparent dans des fonctions anonymes et des initialiseurs d’objets anonymes.When a query translation injects a transparent identifier, further translation steps propagate the transparent identifier into anonymous functions and anonymous object initializers. Dans ces contextes, les identificateurs transparents ont le comportement suivant :In those contexts, transparent identifiers have the following behavior:

  • Lorsqu’un identificateur transparent se produit en tant que paramètre dans une fonction anonyme, les membres du type anonyme associé sont automatiquement dans la portée dans le corps de la fonction anonyme.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.
  • Lorsqu’un membre avec un identificateur transparent est dans la portée, les membres de ce membre sont également dans la portée.When a member with a transparent identifier is in scope, the members of that member are in scope as well.
  • Lorsqu’un identificateur transparent se produit comme déclarateur de membre dans un initialiseur d’objet anonyme, il introduit un membre avec un identificateur transparent.When a transparent identifier occurs as a member declarator in an anonymous object initializer, it introduces a member with a transparent identifier.
  • Dans les étapes de traduction décrites ci-dessus, les identificateurs transparents sont toujours introduits en même temps que les types anonymes, dans le but de capturer plusieurs variables de portée en tant que membres d’un seul objet.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. Une implémentation de C# est autorisée à utiliser un autre mécanisme que les types anonymes pour regrouper plusieurs variables de portée.An implementation of C# is permitted to use a different mechanism than anonymous types to group together multiple range variables. Les exemples de traduction suivants supposent que les types anonymes sont utilisés et montrent comment les identificateurs transparents peuvent être traduits.The following translation examples assume that anonymous types are used, and show how transparent identifiers can be translated away.

L’exempleThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.Total }

est traduit enis translated into

from * in customers.
    SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.Total }

qui est ensuite traduite enwhich is further translated into

customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(* => o.Total).
Select(* => new { c.Name, o.Total })

qui, lorsque les identificateurs transparents sont effacés, est équivalent à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 })

x est un identificateur généré par le compilateur qui est autrement invisible et inaccessible.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

L’exempleThe 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 }

est traduit enis 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 }

ce qui est encore plus réduit àwhich 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 })

traduction finale de qui estthe 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 })

x, y et z sont des identificateurs générés par le compilateur qui, sinon, sont inaccessibles et inaccessibles.where x, y, and z are compiler generated identifiers that are otherwise invisible and inaccessible.

Modèle d’expression de requêteThe query expression pattern

Le modèle d’expression de requête établit un modèle de méthodes que les types peuvent implémenter pour prendre en charge les expressions de requête.The Query expression pattern establishes a pattern of methods that types can implement to support query expressions. Étant donné que les expressions de requête sont traduites en appels de méthode au moyen d’un mappage syntaxique, les types ont une flexibilité considérable dans la manière dont ils implémentent le modèle d’expression de requête.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. Par exemple, les méthodes du modèle peuvent être implémentées en tant que méthodes d’instance ou en tant que méthodes d’extension, car les deux ont la même syntaxe d’appel, et les méthodes peuvent demander des délégués ou des arborescences d’expressions, car les fonctions anonymes sont convertibles dans les deux.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.

La forme recommandée d’un type générique C<T> qui prend en charge le modèle d’expression de requête est illustrée ci-dessous.The recommended shape of a generic type C<T> that supports the query expression pattern is shown below. Un type générique est utilisé pour illustrer les relations appropriées entre les types de paramètres et de résultats, mais il est possible d’implémenter le modèle pour les types non génériques également.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; }
}

Les méthodes ci-dessus utilisent les types délégués génériques Func<T1,R> et Func<T1,T2,R>, mais elles peuvent également avoir utilisé d’autres types de délégué ou d’arborescence d’expression avec les mêmes relations dans les types de paramètres et de résultats.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.

Notez la relation recommandée entre C<T> et O<T>, qui garantit que les méthodes ThenBy et ThenByDescending sont uniquement disponibles sur le résultat d’un OrderBy ou 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. Notez également la forme recommandée du résultat de GroupBy--une séquence de séquences, où chaque séquence interne a une propriété Key supplémentaire.Also notice the recommended shape of the result of GroupBy -- a sequence of sequences, where each inner sequence has an additional Key property.

L’espace de noms System.Linq fournit une implémentation du modèle d’opérateur de requête pour tout type qui implémente l’interface System.Collections.Generic.IEnumerable<T>.The System.Linq namespace provides an implementation of the query operator pattern for any type that implements the System.Collections.Generic.IEnumerable<T> interface.

Opérateurs d'assignationAssignment operators

Les opérateurs d’assignation affectent une nouvelle valeur à une variable, une propriété, un événement ou un élément d’indexeur.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
    ;

L’opérande gauche d’une assignation doit être une expression classifiée comme une variable, un accès à une propriété, un accès à un indexeur ou un accès à un événement.The left operand of an assignment must be an expression classified as a variable, a property access, an indexer access, or an event access.

L’opérateur = est appelé opérateur d’assignation simple.The = operator is called the simple assignment operator. Elle assigne la valeur de l’opérande droit à la variable, à la propriété ou à l’élément d’indexeur donné par l’opérande gauche.It assigns the value of the right operand to the variable, property, or indexer element given by the left operand. L’opérande gauche de l’opérateur d’assignation simple ne peut pas être un accès à un événement (sauf s’il est décrit dans événements de type champ).The left operand of the simple assignment operator may not be an event access (except as described in Field-like events). L’opérateur d’assignation simple est décrit dans assignation simple.The simple assignment operator is described in Simple assignment.

Les opérateurs d’assignation autres que l’opérateur = sont appelés des opérateurs d’assignation composée.The assignment operators other than the = operator are called the compound assignment operators. Ces opérateurs effectuent l’opération indiquée sur les deux opérandes, puis assignent la valeur résultante à la variable, à la propriété ou à l’élément d’indexeur donné par l’opérande gauche.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. Les opérateurs d’assignation composée sont décrits dans assignation composée.The compound assignment operators are described in Compound assignment.

Les opérateurs += et -= avec une expression d’accès à l’événement comme opérande gauche sont appelés opérateurs d’assignation d’événement.The += and -= operators with an event access expression as the left operand are called the event assignment operators. Aucun autre opérateur d’assignation n’est valide avec un accès aux événements comme opérande de gauche.No other assignment operator is valid with an event access as the left operand. Les opérateurs d’assignation d’événement sont décrits dans assignation d’événement.The event assignment operators are described in Event assignment.

Les opérateurs d’assignation sont associatifs à droite, ce qui signifie que les opérations sont regroupées de droite à gauche.The assignment operators are right-associative, meaning that operations are grouped from right to left. Par exemple, une expression de la forme a = b = c est évaluée comme a = (b = c).For example, an expression of the form a = b = c is evaluated as a = (b = c).

Assignation simpleSimple assignment

L’opérateur = est appelé opérateur d’assignation simple.The = operator is called the simple assignment operator.

Si l’opérande gauche d’une assignation simple se présente sous la forme E.P ou E[Ei]E a le type au moment de la compilation dynamic, l’assignation est liée dynamiquement (liaison dynamique).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). Dans ce cas, le type au moment de la compilation de l’expression d’assignation est dynamic, et la résolution décrite ci-dessous s’effectue au moment de l’exécution en fonction du type d’exécution de 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.

Dans une assignation simple, l’opérande de droite doit être une expression implicitement convertible en type de l’opérande de gauche.In a simple assignment, the right operand must be an expression that is implicitly convertible to the type of the left operand. L’opération assigne la valeur de l’opérande droit à la variable, à la propriété ou à l’élément d’indexeur donné par l’opérande gauche.The operation assigns the value of the right operand to the variable, property, or indexer element given by the left operand.

Le résultat d’une expression d’assignation simple est la valeur assignée à l’opérande de gauche.The result of a simple assignment expression is the value assigned to the left operand. Le résultat a le même type que l’opérande de gauche et est toujours classifié comme une valeur.The result has the same type as the left operand and is always classified as a value.

Si l’opérande de gauche est un accès à une propriété ou un indexeur, la propriété ou l’indexeur doit avoir un accesseur set.If the left operand is a property or indexer access, the property or indexer must have a set accessor. Si ce n’est pas le cas, une erreur de temps de liaison se produit.If this is not the case, a binding-time error occurs.

Le traitement au moment de l’exécution d’une assignation simple de la forme x = y comprend les étapes suivantes :The run-time processing of a simple assignment of the form x = y consists of the following steps:

  • Si x est classée en tant que variable :If x is classified as a variable:
    • x est évaluée pour produire la variable.x is evaluated to produce the variable.
    • y est évalué et, si nécessaire, est converti en type de x via une conversion implicite (conversions implicites).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • Si la variable fournie par x est un élément de tableau d’un reference_type, une vérification au moment de l’exécution est effectuée pour s’assurer que la valeur calculée pour y est compatible avec l’instance de tableau dont x est un élément.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. La vérification s’effectue correctement si y est null ou si une conversion de référence implicite (conversions de référence implicites) existe à partir du type réel de l’instance référencée par y vers le type d’élément réel de l’instance de tableau contenant 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. Sinon, une exception System.ArrayTypeMismatchException est levée.Otherwise, a System.ArrayTypeMismatchException is thrown.
    • La valeur résultant de l’évaluation et de la conversion de y est stockée dans l’emplacement donné par l’évaluation de x.The value resulting from the evaluation and conversion of y is stored into the location given by the evaluation of x.
  • Si x est classé comme un accès à une propriété ou un indexeur :If x is classified as a property or indexer access:
    • L’expression d’instance (si x n’est pas static) et la liste d’arguments (si x est un accès à un indexeur) associée à x sont évaluées, et les résultats sont utilisés dans l’appel d’accesseur set suivant.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 est évalué et, si nécessaire, est converti en type de x via une conversion implicite (conversions implicites).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • L’accesseur set de x est appelé avec la valeur calculée pour y comme argument value.The set accessor of x is invoked with the value computed for y as its value argument.

Les règles de covariance de tableau (covariance de tableau) permettent à une valeur d’un type tableau A[] d’être une référence à une instance d’un type tableau B[], à condition qu’il existe une conversion de référence implicite de B en 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. En raison de ces règles, l’assignation à un élément de tableau d’un reference_type requiert un contrôle à l’exécution pour garantir que la valeur assignée est compatible avec l’instance de tableau.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. Dans l’exempleIn the example

string[] sa = new string[10];
object[] oa = sa;

oa[0] = null;               // Ok
oa[1] = "Hello";            // Ok
oa[2] = new ArrayList();    // ArrayTypeMismatchException

la dernière assignation provoque la levée d’une System.ArrayTypeMismatchException, car une instance de ArrayList ne peut pas être stockée dans un élément d’un 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[].

Lorsqu’une propriété ou un indexeur déclaré dans un struct_type est la cible d’une assignation, l’expression d’instance associée à l’accès à la propriété ou à l’indexeur doit être classée en tant que variable.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. Si l’expression d’instance est classée en tant que valeur, une erreur de liaison au moment de la liaison se produit.If the instance expression is classified as a value, a binding-time error occurs. En raison de l' accès aux membres, la même règle s’applique également aux champs.Because of Member access, the same rule also applies to fields.

Compte tenu des déclarations :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; }
    }
}

Dans l’exemplein 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;

les assignations à p.X, p.Y, r.A et r.B sont autorisées, car p et r sont des variables.the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. Toutefois, dans l’exempleHowever, in the example

Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;

les attributions ne sont pas valides, car r.A et r.B ne sont pas des variables.the assignments are all invalid, since r.A and r.B are not variables.

Assignation composéeCompound assignment

Si l’opérande gauche d’une assignation composée se présente sous la forme E.P ou E[Ei]E a le type au moment de la compilation dynamic, l’assignation est liée dynamiquement (liaison dynamique).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). Dans ce cas, le type au moment de la compilation de l’expression d’assignation est dynamic, et la résolution décrite ci-dessous s’effectue au moment de l’exécution en fonction du type d’exécution de 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.

Une opération de la forme x op= y est traitée en appliquant la résolution de surcharge d’opérateur binaire (résolution de surcharge d’opérateur binaire) comme si l’opération avait été écrite 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. CliquezThen,

  • Si le type de retour de l’opérateur sélectionné est implicitement convertible en type de x, l’opération est évaluée comme x = x op y, sauf que x n’est évaluée qu’une seule fois.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.
  • Sinon, si l’opérateur sélectionné est un opérateur prédéfini, si le type de retour de l’opérateur sélectionné est explicitement convertible en type de x, et si y est implicitement convertible en type de x ou si l’opérateur est un opérateur de décalage , l’opération est évaluée comme x = (T)(x op y), où T est le type de x, sauf que x est évaluée une seule fois.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.
  • Dans le cas contraire, l’assignation composée n’est pas valide et une erreur de liaison s’est produite.Otherwise, the compound assignment is invalid, and a binding-time error occurs.

Le terme « évalué une seule fois » signifie que, lors de l’évaluation de x op y, les résultats de toutes les expressions constitut