ExpressõesExpressions

Uma expressão é uma sequência de operadores e operandos.An expression is a sequence of operators and operands. Este capítulo define a sintaxe, a ordem de avaliação dos operandos e operadores e o significado das expressões.This chapter defines the syntax, order of evaluation of operands and operators, and meaning of expressions.

Classificações de expressãoExpression classifications

Uma expressão é classificada como um dos seguintes:An expression is classified as one of the following:

  • Um valor.A value. Cada valor tem um tipo associado.Every value has an associated type.
  • Uma variável.A variable. Cada variável tem um tipo associado, ou seja, o tipo declarado da variável.Every variable has an associated type, namely the declared type of the variable.
  • Um namespace.A namespace. Uma expressão com essa classificação só pode aparecer como o lado esquerdo de uma member_access (acesso de membro).An expression with this classification can only appear as the left hand side of a member_access (Member access). Em qualquer outro contexto, uma expressão classificada como um namespace causa um erro de tempo de compilação.In any other context, an expression classified as a namespace causes a compile-time error.
  • Um tipo.A type. Uma expressão com essa classificação só pode aparecer como o lado esquerdo de uma member_access (acesso de membro), ou como um operando para o as operador (o operador ), o is operador (o operador is), ou o typeof operador (o operador 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). Em qualquer outro contexto, uma classificado como um tipo de expressão causa um erro de tempo de compilação.In any other context, an expression classified as a type causes a compile-time error.
  • Um grupo de método, que é um conjunto de métodos sobrecarregados resultante de uma pesquisa de membro (pesquisa de membro).A method group, which is a set of overloaded methods resulting from a member lookup (Member lookup). Um grupo de método pode ter uma expressão de instância associada e uma lista de argumentos de tipo associado.A method group may have an associated instance expression and an associated type argument list. Quando um método de instância é invocado, o resultado da avaliação da expressão de instância torna-se a instância representada pelo this (esse acesso).When an instance method is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access). Um grupo de métodos é permitido em uma invocation_expression (expressões de invocação), uma delegate_creation_expression (delegar a criação expressões) e como o lado esquerdo de um é o operador e pode ser convertido implicitamente em um tipo de delegado compatível (conversões de grupo de método).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). Em qualquer outro contexto, uma expressão classificada como um grupo de métodos causa um erro de tempo de compilação.In any other context, an expression classified as a method group causes a compile-time error.
  • Um literal nulo.A null literal. Uma expressão com essa classificação pode ser convertida implicitamente para um tipo de referência ou tipo anulável.An expression with this classification can be implicitly converted to a reference type or nullable type.
  • Uma função anônima.An anonymous function. Uma expressão com essa classificação pode ser implicitamente convertida para um tipo de delegado compatível ou tipo de árvore de expressão.An expression with this classification can be implicitly converted to a compatible delegate type or expression tree type.
  • Um acesso de propriedade.A property access. Todo acesso de propriedade tem um tipo associado, ou seja, o tipo da propriedade.Every property access has an associated type, namely the type of the property. Além disso, um acesso de propriedade pode ter uma expressão de instância associada.Furthermore, a property access may have an associated instance expression. Quando um acessador (o get ou set bloco) de uma instância de acesso de propriedade é invocado, o resultado da avaliação da expressão de instância torna-se a instância representada pelo this (esse acesso).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).
  • Acesso de um evento.An event access. Acesso de cada evento tem um tipo associado, ou seja, o tipo do evento.Every event access has an associated type, namely the type of the event. Além disso, o acesso de um evento pode ter uma expressão de instância associada.Furthermore, an event access may have an associated instance expression. Um acesso de evento pode aparecer como o operando à esquerda do += e -= operadores (atribuição de evento).An event access may appear as the left hand operand of the += and -= operators (Event assignment). Em qualquer outro contexto, uma expressão classificada como um acesso de evento causa um erro de tempo de compilação.In any other context, an expression classified as an event access causes a compile-time error.
  • Acesso de um indexador.An indexer access. Cada acesso do indexador tem um tipo associado, ou seja, o tipo de elemento do indexador.Every indexer access has an associated type, namely the element type of the indexer. Além disso, o acesso de um indexador tem uma expressão de instância associada e uma lista de argumentos associados.Furthermore, an indexer access has an associated instance expression and an associated argument list. Quando um acessador (o get ou set bloco) de um indexador acesso é invocado, o resultado da avaliação da expressão de instância torna-se a instância representada pelo this (esse acesso) e o resultado de Avaliando a lista de argumentos torna-se a lista de parâmetros de invocação.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.
  • nada.Nothing. Isso ocorre quando a expressão é uma invocação de um método com um tipo de retorno void.This occurs when the expression is an invocation of a method with a return type of void. Uma expressão classificada como nada só é válido no contexto de um statement_expression (instruções de expressão).An expression classified as nothing is only valid in the context of a statement_expression (Expression statements).

O resultado final de uma expressão nunca é um namespace, tipo, o grupo de método ou acesso ao evento.The final result of an expression is never a namespace, type, method group, or event access. Em vez disso, conforme observado acima, essas categorias de expressões são construções intermediárias que são permitidas somente em determinados contextos.Rather, as noted above, these categories of expressions are intermediate constructs that are only permitted in certain contexts.

Um acesso de propriedade ou o acesso do indexador é sempre reclassificado como um valor pela execução de uma invocação do acessador get ou o acessador 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. O acessador particular é determinado pelo contexto de acesso de propriedade ou indexador: Se o acesso é o destino de uma atribuição, o acessador set é chamado para atribuir um novo valor (atribuição simples).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). Caso contrário, o acessador get é chamado para obter o valor atual (valores das expressões).Otherwise, the get accessor is invoked to obtain the current value (Values of expressions).

Valores de expressõesValues of expressions

A maioria das construções que envolvem uma expressão, por fim, exige que a expressão para denotar uma valor.Most of the constructs that involve an expression ultimately require the expression to denote a value. Nesses casos, se a expressão real denota um namespace, um tipo, um grupo de métodos ou nada, ocorrerá um erro de tempo de compilação.In such cases, if the actual expression denotes a namespace, a type, a method group, or nothing, a compile-time error occurs. No entanto, se a expressão denota um acesso de propriedade, um acesso de indexador ou uma variável, o valor da propriedade, indexador ou variável implicitamente é substituído: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:

  • O valor de uma variável é simplesmente o valor armazenado atualmente no local de armazenamento identificado pela variável.The value of a variable is simply the value currently stored in the storage location identified by the variable. Uma variável deve ser considerada atribuída definitivamente (atribuição definitiva) antes de seu valor pode ser obtido ou, caso contrário, ocorrerá um erro de tempo de compilação.A variable must be considered definitely assigned (Definite assignment) before its value can be obtained, or otherwise a compile-time error occurs.
  • O valor de uma expressão de acesso de propriedade é obtido invocando o acessador get da propriedade.The value of a property access expression is obtained by invoking the get accessor of the property. Se a propriedade não tiver nenhuma acessador get, ocorre um erro de tempo de compilação.If the property has no get accessor, a compile-time error occurs. Caso contrário, uma invocação de membro de função (verificação de resolução de sobrecarga de dinâmica de tempo de compilação) é executada, e o resultado da invocação se tornará o valor da expressão de acesso de propriedade.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.
  • O valor de uma expressão de acesso do indexador é obtido invocando o acessador get do indexador.The value of an indexer access expression is obtained by invoking the get accessor of the indexer. Se o indexador não tiver nenhuma acessador get, ocorre um erro de tempo de compilação.If the indexer has no get accessor, a compile-time error occurs. Caso contrário, uma invocação de membro de função (verificação de resolução de sobrecarga de dinâmica de tempo de compilação) é executada com o argumento de lista associado com a expressão de acesso do indexador e o resultado da invocação se tornará o valor da expressão de acesso do indexador.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.

Associação estática e dinâmicaStatic and Dynamic Binding

O processo de determinar o significado de uma operação com base no tipo ou valor de expressões constituintes (argumentos, operandos, receptores) é geralmente denominado associação.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. Por exemplo o significado de uma chamada de método é determinado com base no tipo dos argumentos e o receptor.For instance the meaning of a method call is determined based on the type of the receiver and arguments. O significado de um operador é determinado com base no tipo de seus operandos.The meaning of an operator is determined based on the type of its operands.

Em c# o significado de uma operação normalmente é determinada em tempo de compilação, com base no tipo de tempo de compilação das suas expressões constituintes.In C# the meaning of an operation is usually determined at compile-time, based on the compile-time type of its constituent expressions. Da mesma forma, se uma expressão contiver um erro, o erro é detectado e reportado pelo compilador.Likewise, if an expression contains an error, the error is detected and reported by the compiler. Essa abordagem é conhecida como vinculação estática.This approach is known as static binding.

No entanto, se uma expressão é uma expressão dinâmica (ou seja, tem o tipo dynamic) indica que qualquer ligação que participa do deve ser baseada em seu tipo de tempo de execução (ou seja, o tipo real do objeto, ele indicará em tempo de execução) em vez do tipo tem no tempo de compilação.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. A associação dessa operação, portanto, é adiada até o momento em que a operação deve ser executado durante a execução do programa.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. Isso é conhecido como vinculação dinâmica.This is referred to as dynamic binding.

Quando uma operação é vinculada dinamicamente, pouca ou nenhuma verificação é executada pelo compilador.When an operation is dynamically bound, little or no checking is performed by the compiler. Em vez disso, se a associação de tempo de execução falhar, os erros são relatados como exceções em tempo de execução.Instead if the run-time binding fails, errors are reported as exceptions at run-time.

As seguintes operações em c# estão sujeitos a associação:The following operations in C# are subject to binding:

  • Acesso de membro: e.MMember access: e.M
  • Invocação de método: e.M(e1, ..., eN)Method invocation: e.M(e1, ..., eN)
  • Invocação de delegado:e(e1, ..., eN)Delegate invocation:e(e1, ..., eN)
  • Acesso de elemento: e[e1, ..., eN]Element access: e[e1, ..., eN]
  • Criação do objeto: new C(e1, ..., eN)Object creation: new C(e1, ..., eN)
  • Operadores unários sobrecarregados: +, -, !, ~, ++, --, true, falseOverloaded unary operators: +, -, !, ~, ++, --, true, false
  • Sobrecarga dos operadores binários: +, -, *, /, %, &, &&, |, ||, ??, ^, << , >>, ==,!=, >, <, >=, <=Overloaded binary operators: +, -, *, /, %, &, &&, |, ||, ??, ^, <<, >>, ==,!=, >, <, >=, <=
  • Operadores de atribuição: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=Assignment operators: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
  • Conversões implícitas e explícitasImplicit and explicit conversions

Quando não há expressões dinâmicas estão envolvidas, c# assume como padrão a vinculação estática, o que significa que os tipos de tempo de compilação de expressões constituintes são usados no processo de seleção.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. No entanto, quando uma das expressões constituintes nas operações listadas acima é uma expressão dinâmica, a operação em vez disso, vinculada dinamicamente.However, when one of the constituent expressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound.

Tempo de associaçãoBinding-time

Vinculação estática ocorre em tempo de compilação, ao passo que a vinculação dinâmica ocorre em tempo de execução.Static binding takes place at compile-time, whereas dynamic binding takes place at run-time. Nas seções a seguir, o termo tempo de associação refere-se ao tempo de compilação ou tempo de execução, dependendo de quando ocorre a associação.In the following sections, the term binding-time refers to either compile-time or run-time, depending on when the binding takes place.

O exemplo a seguir ilustra as noções de associação estática e dinâmica e de tempo de associação: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)

As duas primeiras chamadas são vinculadas estaticamente: a sobrecarga de Console.WriteLine é escolhida com base no tipo de tempo de compilação do seu argumento.The first two calls are statically bound: the overload of Console.WriteLine is picked based on the compile-time type of their argument. Assim, o tempo de associação é o tempo de compilação.Thus, the binding-time is compile-time.

A terceira chamada associada dinamicamente: a sobrecarga de Console.WriteLine é escolhida com base no tipo de tempo de execução do seu argumento.The third call is dynamically bound: the overload of Console.WriteLine is picked based on the run-time type of its argument. Isso acontece porque o argumento é uma expressão dinâmica – seu tipo de tempo de compilação é dynamic.This happens because the argument is a dynamic expression -- its compile-time type is dynamic. Portanto, o tempo de associação para a terceira chamada é o tempo de execução.Thus, the binding-time for the third call is run-time.

Associação dinâmicaDynamic binding

A finalidade de associação dinâmica é permitir que programas em c# interagir com objetos dinâmicos, ou seja, sistema de tipos de objetos que não seguem as regras normais do c#.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. Objetos dinâmicos podem ser objetos de outras linguagens de programação com sistemas de tipos diferentes, ou podem ser objetos por meio de programação são configuradas para implementar suas próprias semânticas de associação para operações diferentes.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.

O mecanismo pelo qual um objeto dinâmico implementa seu próprio semântica é definido pela implementação.The mechanism by which a dynamic object implements its own semantics is implementation defined. Uma determinada interface – novamente definido pela implementação – é implementada por objetos dinâmicos para sinalizar para o c# tempo de execução que eles têm semântica especial.A given interface -- again implementation defined -- is implemented by dynamic objects to signal to the C# run-time that they have special semantics. Assim, sempre que as operações em um objeto dinâmico são vinculadas dinamicamente, suas próprias semânticas de associação, em vez da linguagem c#, conforme especificado neste documento, assumir.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.

Enquanto a finalidade de associação dinâmica é permitir a interoperação com objetos dinâmicos, c# permite a associação dinâmica em todos os objetos, independentemente de estarem dinâmicos ou não.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. Isso permite uma integração mais suave de objetos dinâmicos, como os resultados das operações neles talvez por si próprios ser objetos dinâmicos, mas são ainda de um tipo desconhecido para o programador em tempo de compilação.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. Também a vinculação dinâmica pode ajudar a eliminar o código de baseados em reflexão propenso a erro mesmo quando não há objetos envolvidos são objetos dinâmicos.Also dynamic binding can help eliminate error-prone reflection-based code even when no objects involved are dynamic objects.

As seções a seguir descrevem cada constructo no idioma for exatamente quando vinculação dinâmica é aplicada, o que compilar a verificação de tempo – se qualquer um-- é aplicada e qual classificação de resultados e a expressão de tempo de compilação é.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.

Tipos de expressões constituintesTypes of constituent expressions

Quando uma operação é vinculada estaticamente, o tipo de uma expressão constituinte (por exemplo, um destinatário, um argumento, um índice ou um operando) é sempre considerado como o tipo de tempo de compilação dessa expressão.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.

Quando uma operação dinamicamente é vinculada, o tipo de uma expressão constituinte é determinado de maneiras diferentes dependendo do tipo de tempo de compilação da expressão constituinte: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:

  • Uma expressão constituinte do tipo de tempo de compilação dynamic é considerado como tendo o tipo do valor real que a expressão é avaliada em tempo de execuçãoA constituent expression of compile-time type dynamic is considered to have the type of the actual value that the expression evaluates to at runtime
  • Uma expressão constituinte cujo tipo de tempo de compilação é um parâmetro de tipo é considerada como tendo o tipo que o parâmetro de tipo é associado em tempo de execuçãoA 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
  • Caso contrário, a expressão constituinte é considerada como tendo seu tipo de tempo de compilação.Otherwise the constituent expression is considered to have its compile-time type.

OperadoresOperators

Expressões são construídas a partir operandos e operadores.Expressions are constructed from operands and operators. Os operadores de uma expressão indicam quais operações devem ser aplicadas aos operandos.The operators of an expression indicate which operations to apply to the operands. Exemplos de operadores incluem +, -, *, / e new.Examples of operators include +, -, *, /, and new. Exemplos de operandos incluem literais, campos, variáveis locais e expressões.Examples of operands include literals, fields, local variables, and expressions.

Há três tipos de operadores:There are three kinds of operators:

  • Operadores unários.Unary operators. Os operadores unários usam um operando e usar a notação de prefixo (como --x) ou notação de sufixo (como x++).The unary operators take one operand and use either prefix notation (such as --x) or postfix notation (such as x++).
  • Operadores binários.Binary operators. Os operadores binários usam dois operandos e todas usam a notação de infixo (como x + y).The binary operators take two operands and all use infix notation (such as x + y).
  • operador ternário.Ternary operator. Apenas um operador ternário ?:, existe; ele usa três operandos e usa a notação de infixo (c ? x : y).Only one ternary operator, ?:, exists; it takes three operands and uses infix notation (c ? x : y).

A ordem de avaliação de operadores em uma expressão é determinada pelo precedência e associatividade dos operadores (precedência e associatividade) .The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators (Operator precedence and associativity).

Os operandos em uma expressão são avaliados da esquerda para a direita.Operands in an expression are evaluated from left to right. Por exemplo, na F(i) + G(i++) * H(i), método F for chamado usando o valor antigo da i, em seguida, o método G é chamado com o valor antigo da ie, finalmente, o método H é chamado com o novo valor 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. Isso é separada e não relacionadas à precedência de operador.This is separate from and unrelated to operator precedence.

Determinados operadores podem ser sobrecarregados.Certain operators can be overloaded. Sobrecarga de operador permite que implementações de operador definido pelo usuário deve ser especificado para operações em que um ou ambos os operandos são de um tipo de classe ou estrutura definida pelo usuário (sobrecarga de operador).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).

Precedência e associatividade do operadorOperator precedence and associativity

Quando uma expressão contiver vários operadores, a precedência dos operadores controla a ordem na qual os operadores individuais são avaliados.When an expression contains multiple operators, the precedence of the operators controls the order in which the individual operators are evaluated. Por exemplo, a expressão x + y * z é avaliado como x + (y * z) porque o * operador tem precedência maior do que o binário + operador.For example, the expression x + y * z is evaluated as x + (y * z) because the * operator has higher precedence than the binary + operator. A precedência de um operador é estabelecida pela definição de sua produção de gramática associado.The precedence of an operator is established by the definition of its associated grammar production. Por exemplo, um additive_expression consiste em uma sequência de multiplicative_expressions separados por + ou - operadores, proporcionando assim a + e - operadores menor precedência que o *, /, e % operadores.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.

A tabela a seguir resume todos os operadores na ordem de precedência da mais alta para a mais baixa:The following table summarizes all operators in order of precedence from highest to lowest:

SectionSection CategoriaCategory OperadoresOperators
Expressões primáriasPrimary expressions PrimáriaPrimary 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
Operadores unáriosUnary operators UnárioUnary + - ! ~ ++x --x (T)x+ - ! ~ ++x --x (T)x
Operadores aritméticosArithmetic operators MultiplicativoMultiplicative * / %* / %
Operadores aritméticosArithmetic operators AditivoAdditive + -+ -
Operadores shiftShift operators ShiftShift << >><< >>
Operadores de teste de tipo e relacionalRelational and type-testing operators Teste de tipo e relacionalRelational and type testing < > <= >= is as< > <= >= is as
Operadores de teste de tipo e relacionalRelational and type-testing operators IgualdadeEquality == !=== !=
Operadores lógicosLogical operators AND lógicoLogical AND &
Operadores lógicosLogical operators XOR lógicoLogical XOR ^
Operadores lógicosLogical operators OR lógicoLogical OR |
Operadores lógicos condicionaisConditional logical operators AND condicionalConditional AND &&
Operadores lógicos condicionaisConditional logical operators OR condicionalConditional OR ||
O operador de coalescência nulaThe null coalescing operator Coalescência nulaNull coalescing ??
Operador condicionalConditional operator CondicionalConditional ?:
Operadores de atribuição, expressões de função anônimaAssignment operators, Anonymous function expressions Atribuição e expressão lambdaAssignment and lambda expression = *= /= %= += -= <<= >>= &= ^= |= =>= *= /= %= += -= <<= >>= &= ^= |= =>

Quando ocorre um operando entre dois operadores com a mesma precedência, a associatividade dos operadores controla a ordem na qual as operações são executadas: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:

  • Exceto para os operadores de atribuição e o operador de união nulo, todos os operadores binários são associativos à esquerda, que significa que operações são executadas da esquerda para a direita.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. Por exemplo, x + y + z é avaliado como (x + y) + z.For example, x + y + z is evaluated as (x + y) + z.
  • Os operadores de atribuição, o operador de união nulo e o operador condicional (?:) estão associativo, que significa que as operações são executadas da direita para esquerda.The assignment operators, the null coalescing operator and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. Por exemplo, x = y = z é avaliado como x = (y = z).For example, x = y = z is evaluated as x = (y = z).

Precedência e associatividade podem ser controladas usando parênteses.Precedence and associativity can be controlled using parentheses. Por exemplo, x + y * z primeiro multiplica y por z e, em seguida, adiciona o resultado a x, mas (x + y) * z primeiro adiciona x e y e, em seguida, multiplica o resultado por 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.

Sobrecarga de operadorOperator overloading

Todos os operadores unários e binários têm predefinidos implementações que ficam automaticamente disponíveis em qualquer expressão.All unary and binary operators have predefined implementations that are automatically available in any expression. As implementações predefinidas, além de implementações definidas pelo usuário podem ser introduzidas, incluindo operator declarações em classes e structs (operadores).In addition to the predefined implementations, user-defined implementations can be introduced by including operator declarations in classes and structs (Operators). Implementações de operador definido pelo usuário sempre têm precedência sobre implementações de operadores predefinidos: Somente quando não há implementações aplicável operador definido pelo usuário existem serão as implementações de operador pré-definido ser considerado, conforme descrito em resolução de sobrecarga de operador unário e sobrecarga de operador binário resolução.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.

O operadores sobrecarregáveis unários são:The overloadable unary operators are:

+   -   !   ~   ++   --   true   false

Embora true e false não são explicitamente usados em expressões (e, portanto, não são incluídos na tabela precedência precedência e associatividade), eles são considerados operadores porque eles são invocado em vários contextos de expressão: expressões Boolianas (expressões Boolianas) e expressões que envolvem a condicional (operador condicional) e condicional lógico operadores (operadores lógicos condicionais).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).

O sobrecarregáveis operadores binários são:The overloadable binary operators are:

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

Somente os operadores listados acima podem ser sobrecarregados.Only the operators listed above can be overloaded. Em particular, não é possível sobrecarregar o acesso de membro de invocação de método, ou o =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, as, e is operadores.In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, as, and is operators.

Quando um operador binário está sobrecarregado, o operador de atribuição correspondente, se houver, também estará implicitamente sobrecarregado.When a binary operator is overloaded, the corresponding assignment operator, if any, is also implicitly overloaded. Por exemplo, uma sobrecarga de operador * também é uma sobrecarga de operador *=.For example, an overload of operator * is also an overload of operator *=. Isso é descrito posteriormente em atribuição composta.This is described further in Compound assignment. Observe que o operador de atribuição (=) não pode ser sobrecarregado.Note that the assignment operator itself (=) cannot be overloaded. Uma atribuição sempre executa uma simple cópia bit a bit de um valor em uma variável.An assignment always performs a simple bit-wise copy of a value into a variable.

Converter operações, como (T)x, estão sobrecarregados, fornecendo conversões definidas pelo usuário (conversões definidas pelo usuário).Cast operations, such as (T)x, are overloaded by providing user-defined conversions (User-defined conversions).

Acesso de elemento, como a[x], não é considerado um operador que pode ser sobrecarregado.Element access, such as a[x], is not considered an overloadable operator. Em vez disso, a indexação de definida pelo usuário tem suporte por meio de indexadores (indexadores).Instead, user-defined indexing is supported through indexers (Indexers).

Em expressões, operadores são referenciados usando a notação do operador e em declarações, operadores são referenciados usando a notação funcional.In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. A tabela a seguir mostra a relação entre o operador e notações funcionais para o operador unário ou binário.The following table shows the relationship between operator and functional notations for unary and binary operators. Na primeira entrada, op denota qualquer operador de prefixo unário que pode ser sobrecarregado.In the first entry, op denotes any overloadable unary prefix operator. Na segunda entrada, op denota o sufixo unário ++ e -- operadores.In the second entry, op denotes the unary postfix ++ and -- operators. Na entrada do terceiro op denota qualquer operador binário que pode ser sobrecarregado.In the third entry, op denotes any overloadable binary operator.

Notação do operadorOperator notation Notação funcionalFunctional notation
op x operator op(x)
x op operator op(x)
x op y operator op(x,y)

Declarações de operador definido pelo usuário sempre exigem pelo menos um dos parâmetros para ser do tipo de classe ou struct que contém a declaração do operador.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. Portanto, não é possível para um operador definido pelo usuário ter a mesma assinatura como um operador predefinido.Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.

Declarações de operador definido pelo usuário não é possível modificar a sintaxe, a precedência ou a associatividade do operador.User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. Por exemplo, o / operador é sempre um operador binário, sempre tem o nível de precedência especificada no precedência e associatividadee é sempre associativos à esquerda.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.

Embora seja possível para um operador definido pelo usuário executar qualquer cálculo, o que desejar, implementações que produzem resultados diferentes daqueles que intuitivamente são esperados são altamente desaconselhável.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. Por exemplo, uma implementação de operator == deve comparar os dois operandos quanto à igualdade e retornar um apropriado bool resultado.For example, an implementation of operator == should compare the two operands for equality and return an appropriate bool result.

As descrições dos operadores individuais na expressões primárias por meio operadores lógicos condicionais especificar as implementações predefinidas de operadores e todas as regras adicionais que se aplicam para cada operador.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. Verifique as descrições de usar os termos resolução de sobrecarga de operador unário, resolução de sobrecarga de operador binário, e promoção numérica, definições de quais são encontrado nas seções a seguir.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.

Resolução de sobrecarga de operador unárioUnary operator overload resolution

Uma operação do formulário op x ou x op, onde op é um operador unário que pode ser sobrecarregado, e x é uma expressão do tipo X, é processado da seguinte maneira: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:

  • O conjunto de operadores definidos pelo usuário de candidato fornecidos pelo X para a operação operator op(x) é determinado usando as regras da operadores definidos pelo usuário do candidato.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.
  • Se o conjunto de operadores definidos pelo usuário do candidato não estiver vazio, em seguida, isso se torna o conjunto de operadores de candidato para a operação.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Caso contrário, o operador unário de predefinidos operator op implementações, incluindo seus formulários elevados, tornam-se o conjunto de operadores de candidato para a operação.Otherwise, the predefined unary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. As implementações predefinidas de um determinado operador são especificadas na descrição do operador (expressões primárias e operadores unários).The predefined implementations of a given operator are specified in the description of the operator (Primary expressions and Unary operators).
  • As regras de resolução de sobrecarga resolução de sobrecarga são aplicadas ao conjunto de operadores de candidato para selecionar o operador de melhor em relação à lista de argumentos (x), e este operador torna-se o resultado da sobrecarga processo de resolução.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. Se a resolução de sobrecarga não selecionar um único operador melhor, ocorrerá um erro de tempo de associação.If overload resolution fails to select a single best operator, a binding-time error occurs.

Resolução de sobrecarga de operador binárioBinary operator overload resolution

Uma operação do formulário x op y, onde op é um operador binário que pode ser sobrecarregado, x é uma expressão do tipo X, e y é uma expressão do tipo Y, é processado da seguinte maneira: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:

  • O conjunto de operadores definidos pelo usuário de candidato fornecidos pelo X e Y para a operação operator op(x,y) é determinado.The set of candidate user-defined operators provided by X and Y for the operation operator op(x,y) is determined. O conjunto consiste na união dos operadores candidato fornecidos pelo X e os operadores de candidato fornecidos pelo Y, cada determinado usando as regras da operadores definidos pelo usuário do candidato.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. Se X e Y são do mesmo tipo, ou se X e Y são derivados de um tipo de base comum, em seguida, operadores de candidato compartilhado ocorrerem somente em conjunto combinado uma vez.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.
  • Se o conjunto de operadores definidos pelo usuário do candidato não estiver vazio, em seguida, isso se torna o conjunto de operadores de candidato para a operação.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Caso contrário, o binário predefinido operator op implementações, incluindo seus formulários elevados, tornam-se o conjunto de operadores de candidato para a operação.Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. As implementações predefinidas de um determinado operador são especificadas na descrição do operador (operadores aritméticos por meio operadores lógicos condicionais).The predefined implementations of a given operator are specified in the description of the operator (Arithmetic operators through Conditional logical operators). Para os operadores predefinidos para enum e delegado, os operadores apenas considerados são aquelas definidas por um tipo de enum ou delegado que é o tipo de tempo de associação de um dos operandos.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.
  • As regras de resolução de sobrecarga resolução de sobrecarga são aplicadas ao conjunto de operadores de candidato para selecionar o operador de melhor em relação à lista de argumentos (x,y), e este operador torna-se o resultado da sobrecarga processo de resolução.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. Se a resolução de sobrecarga não selecionar um único operador melhor, ocorrerá um erro de tempo de associação.If overload resolution fails to select a single best operator, a binding-time error occurs.

Operadores definidos pelo usuário do candidatoCandidate user-defined operators

Dado um tipo T e uma operação operator op(A), onde op é um operador que pode ser sobrecarregado e A é uma lista de argumentos, o conjunto de candidatos operadores definidos pelo usuário fornecidos pelo T para operator op(A) é determinada da seguinte maneira: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:

  • Determinar o tipo T0.Determine the type T0. Se T é um tipo anulável, T0 é o seu tipo subjacente, caso contrário T0 é igual a T.If T is a nullable type, T0 is its underlying type, otherwise T0 is equal to T.
  • Para todos os operator op declarações na T0 e todas as retiradas formas desses operadores, se pelo menos um operador é aplicável (membro da função aplicável) em relação à lista de argumentos A, em seguida, o conjunto de operadores de candidato consiste em todos os tais operadores aplicáveis na 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.
  • Caso contrário, se T0 é object, o conjunto de operadores de release candidate está vazio.Otherwise, if T0 is object, the set of candidate operators is empty.
  • Caso contrário, o conjunto de operadores de candidato fornecidos pelo T0 é o conjunto de operadores de candidato fornecidos pela classe base direta de T0, ou a classe base efetiva de T0 se T0 é um parâmetro de tipo.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.

Promoções numéricasNumeric promotions

Promoção numérica consiste em realizar automaticamente determinadas conversões implícitas de operandos dos operadores numéricos binários e unária predefinida.Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. Promoção numérica não é um mecanismo distinto, mas em vez disso, um efeito de aplicar a resolução de sobrecarga para os operadores predefinidos.Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. Promoção numérica especificamente não afeta a avaliação dos operadores definidos pelo usuário, embora os operadores definidos pelo usuário podem ser implementados para apresentar efeitos semelhantes.Numeric promotion specifically does not affect evaluation of user-defined operators, although user-defined operators can be implemented to exhibit similar effects.

Como um exemplo de promoção numérico, considere as implementações predefinidas do binário * operador: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);

Quando as regras de resolução de sobrecarga (resolução de sobrecarga) são aplicadas a esse conjunto de operadores, o efeito é selecionar o primeiro dos operadores para o qual existem conversões implícitas entre os tipos de operando.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. Por exemplo, para a operação b * s, onde b é um byte e s é um short, seleciona de resolução de sobrecarga operator *(int,int) como o operador melhor.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. Portanto, o efeito é que b e s são convertidos em int, e o tipo do resultado é int.Thus, the effect is that b and s are converted to int, and the type of the result is int. Da mesma forma, para a operação i * d, onde i é um int e d é um double, seleciona de resolução de sobrecarga operator *(double,double) como o operador melhor.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.

Promoções de numérico unárioUnary numeric promotions

Promoção de unário numérica ocorre para os operandos de predefinida +, -, e ~ operadores unários.Unary numeric promotion occurs for the operands of the predefined +, -, and ~ unary operators. Promoção de numérico unária consiste apenas em operandos do tipo de conversão sbyte, byte, short, ushort, ou char digitar int.Unary numeric promotion simply consists of converting operands of type sbyte, byte, short, ushort, or char to type int. Além disso, para o operador unário - operador unário de promoção numérico converte operandos do tipo uint digitar long.Additionally, for the unary - operator, unary numeric promotion converts operands of type uint to type long.

Promoções numéricas bináriasBinary numeric promotions

Promoção de numérica binária ocorre para os operandos de predefinida +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, e <= operadores binários.Binary numeric promotion occurs for the operands of the predefined +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. Promoção numérica binária implicitamente converte ambos os operandos em um tipo comum que, no caso dos operadores relacionais, também se tornará o tipo de resultado da operação.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. Promoção de numérica binária consiste em Aplicar regras a seguir, na ordem em que eles aparecem aqui:Binary numeric promotion consists of applying the following rules, in the order they appear here:

  • Se qualquer operando for do tipo decimal, o outro operando será convertido ao tipo decimal, ou um erro em tempo de vinculação ocorrerá se o outro operando for do tipo 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.
  • Caso contrário, se qualquer operando for do tipo double, o outro operando será convertido ao tipo double.Otherwise, if either operand is of type double, the other operand is converted to type double.
  • Caso contrário, se qualquer operando for do tipo float, o outro operando será convertido ao tipo float.Otherwise, if either operand is of type float, the other operand is converted to type float.
  • Caso contrário, se qualquer operando for do tipo ulong, o outro operando será convertido ao tipo ulong, ou um erro em tempo de vinculação ocorrerá se o outro operando for do tipo 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.
  • Caso contrário, se qualquer operando for do tipo long, o outro operando será convertido ao tipo long.Otherwise, if either operand is of type long, the other operand is converted to type long.
  • Caso contrário, se qualquer operando for do tipo uint e o outro operando for do tipo sbyte, short, ou int, ambos os operandos serão convertidos ao tipo 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.
  • Caso contrário, se qualquer operando for do tipo uint, o outro operando será convertido ao tipo uint.Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • Caso contrário, os dois operandos serão convertidos ao tipo int.Otherwise, both operands are converted to type int.

Observe que a primeira regra não permite todas as operações que combinam os decimal tipo com o double e float tipos.Note that the first rule disallows any operations that mix the decimal type with the double and float types. A regra segue do fato de que não há nenhuma conversão implícita entre o decimal tipo e o double e float tipos.The rule follows from the fact that there are no implicit conversions between the decimal type and the double and float types.

Observe também que não é possível que um operando para ser do tipo ulong quando o outro operando for de um tipo integral com sinal.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. O motivo é que existe nenhum tipo integral que pode representar a gama completa de ulong , bem como os tipos integrais com sinal.The reason is that no integral type exists that can represent the full range of ulong as well as the signed integral types.

Em ambos os casos acima, uma expressão de conversão pode ser usada para converter explicitamente um operando em um tipo que é compatível com o outro operando.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.

No exemploIn the example

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

um erro de tempo de associação ocorre porque uma decimal não pode ser multiplicada por uma double.a binding-time error occurs because a decimal cannot be multiplied by a double. O erro seja resolvido com a conversão explícita para o segundo operando decimal, da seguinte maneira: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);
}

Operadores canceladasLifted operators

Eliminada operadores permitir que operadores predefinidos e definidos pelo usuário que operam em tipos de valor não anulável para também ser usados com formulários que permitem valor nulos desses tipos.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. Operadores elevadas são construídos a partir de operadores predefinidos e definidos pelo usuário que atendem a certos requisitos, conforme descrito a seguir:Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:

  • Para os operadores unáriosFor the unary operators

    +  ++  -  --  !  ~
    

    existe em um formato elevado de um operador se os tipos de operando e o resultado são os dois tipos de valor não anulável.a lifted form of an operator exists if the operand and result types are both non-nullable value types. O formulário elevado é construído com a adição de um único ? modificador para os tipos de operando e resultado.The lifted form is constructed by adding a single ? modifier to the operand and result types. O operador elevado produz um valor nulo se o operando for nulo.The lifted operator produces a null value if the operand is null. Caso contrário, o operador cancelado ou não, o operando, aplica o operador subjacente e encapsula o resultado.Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.

  • Para os operadores bináriosFor the binary operators

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

    existe em um formato elevado de um operador se os tipos de operando e o resultado são todos os tipos de valor não anulável.a lifted form of an operator exists if the operand and result types are all non-nullable value types. O formulário elevado é construído com a adição de um único ? modificador para cada tipo de operando e o resultado.The lifted form is constructed by adding a single ? modifier to each operand and result type. O operador elevado produz um valor nulo se um ou ambos os operandos forem nulos (uma exceção que está sendo a & e | operadores da bool? de tipo, conforme descrito em boolianos operadores lógicos).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). Caso contrário, o operador cancelado ou não, os operandos, aplica o operador subjacente e encapsula o resultado.Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.

  • Para os operadores de igualdadeFor the equality operators

    ==  !=
    

    um formulário elevado de um operador existe se os tipos de operando forem tipos de valor não anulável e se o tipo de resultado é 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. O formulário elevado é construído com a adição de um único ? modificador para cada tipo de operando.The lifted form is constructed by adding a single ? modifier to each operand type. O operador elevado considera iguais de dois valores nulos e um valor nulo desiguais para qualquer valor não nulo.The lifted operator considers two null values equal, and a null value unequal to any non-null value. Se ambos os operandos forem não nulos, o operador de cancelada ou não, os operandos e aplica o operador de base para produzir o bool resultado.If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

  • Para os operadores relacionaisFor the relational operators

    <  >  <=  >=
    

    um formulário elevado de um operador existe se os tipos de operando forem tipos de valor não anulável e se o tipo de resultado é 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. O formulário elevado é construído com a adição de um único ? modificador para cada tipo de operando.The lifted form is constructed by adding a single ? modifier to each operand type. O operador elevado produz o valor false se um ou ambos os operandos são nulos.The lifted operator produces the value false if one or both operands are null. Caso contrário, o operador cancelado ou não, os operandos e aplica o operador de base para produzir o bool resultado.Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

Pesquisa de membroMember lookup

Uma pesquisa de membro é o processo pelo qual o significado de um nome no contexto de um tipo é determinado.A member lookup is the process whereby the meaning of a name in the context of a type is determined. Uma pesquisa de membro pode ocorrer como parte da avaliação de uma simple_name (nomes simples) ou uma member_access (acesso de membro) em um expressão.A member lookup can occur as part of evaluating a simple_name (Simple names) or a member_access (Member access) in an expression. Se o simple_name ou member_access ocorre como o primary_expression de uma invocation_expression ( As invocações de método), o membro deve ser invocado.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.

Se um membro é um método ou evento, ou se for uma constante, campo ou propriedade de um tipo de delegado (delegados) ou o tipo dynamic (tipo dinâmico), em seguida, o membro deve ser 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.

Pesquisa de membro considera não apenas o nome de um membro, mas também o número de parâmetros de tipo que do membro e se o membro for acessível.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. Para fins de pesquisa de membro, métodos genéricos e tipos genéricos aninhados têm o número de parâmetros de tipo indicado em suas respectivas declarações e todos os outros membros têm zero parâmetros de tipo.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.

Uma pesquisa de um nome de membro N com K  parâmetros de tipo em um tipo T é processado da seguinte maneira:A member lookup of a name N with K type parameters in a type T is processed as follows:

  • Primeiro, um conjunto de membros acessíveis chamado N é determinado:First, a set of accessible members named N is determined:
    • Se T é um parâmetro de tipo, em seguida, o conjunto é a união dos conjuntos de membros acessíveis nomeados N em cada um dos tipos especificados como uma restrição primária ou restrição secundária (restrições de parâmetro de tipo) para  T, juntamente com o conjunto de membros acessíveis nomeados N em 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.
    • Caso contrário, o conjunto consiste em todos os acessível (acesso de membro) membros nomeados N na T, incluindo membros herdados e os membros acessíveis nomeados N em 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. Se T é um tipo construído, o conjunto de membros é obtido, substituindo os argumentos de tipo, conforme descrito em membros de tipos construídos.If T is a constructed type, the set of members is obtained by substituting type arguments as described in Members of constructed types. Os membros que incluem um override modificador são excluídos do conjunto.Members that include an override modifier are excluded from the set.
  • Em seguida, se K for zero, todos os aninhados de tipos cujas declarações incluem parâmetros de tipo são removidos.Next, if K is zero, all nested types whose declarations include type parameters are removed. Se K for diferente de zero, todos os membros com um número diferente de tipo de parâmetros são removidos.If K is not zero, all members with a different number of type parameters are removed. Observe que, quando K é zero, métodos com parâmetros não forem removidos, desde que o processo de inferência de tipo do tipo (inferência de tipo) pode ser capaz de inferir os argumentos de tipo.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.
  • Em seguida, se o membro é invocado, todos os não-invocable os membros são removidos do conjunto.Next, if the member is invoked, all non-invocable members are removed from the set.
  • Em seguida, os membros que estão ocultos por outros membros são removidos do conjunto.Next, members that are hidden by other members are removed from the set. Para cada membro S.M no conjunto, onde S é o tipo no qual o membro M for declarado, as seguintes regras são aplicadas: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:
    • Se M é uma constante, campo, propriedade, evento ou membro de enumeração, em seguida, todos os membros declarados em um tipo base do S são removidas do conjunto.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.
    • Se M é uma declaração de tipo e, em seguida, todos os tipos que não são declarados em um tipo base de S são removidas do conjunto, e todas as declarações com o mesmo número de parâmetros de tipo como de tipo M declarado em um tipo base do S são removidos do conjunto.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.
    • Se M é um método, em seguida, todos os membros não-método declarado em um tipo base do S são removidas do conjunto.If M is a method, then all non-method members declared in a base type of S are removed from the set.
  • Em seguida, os membros de interface que ficam ocultos por membros de classe são removidos do conjunto.Next, interface members that are hidden by class members are removed from the set. Esta etapa só terá efeito se T é um parâmetro de tipo e T tem os dois uma classe base efetivada diferente de object e uma interface de efetivada vazio definido (restrições de parâmetro de tipo).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). Para cada membro S.M no conjunto, onde S é o tipo no qual o membro M for declarado, as seguintes regras são aplicadas se S é uma declaração de classe diferente de 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:
    • Se M é uma constante, campo, propriedade, evento, membro de enumeração ou declaração de tipo, em seguida, todos os membros declarados na declaração de interface são removidos do conjunto.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.
    • Se M é um método, em seguida, todos os membros não-método declarados em uma declaração de interface são removidos do conjunto e todos os métodos com a mesma assinatura que M declarado em uma interface de declaração são removidos do conjunto.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.
  • Por fim, o resultado da pesquisa de ter removido a membros ocultos, é determinado:Finally, having removed hidden members, the result of the lookup is determined:
    • Se o conjunto consiste em um único membro que não é um método, esse membro é o resultado da pesquisa.If the set consists of a single member that is not a method, then this member is the result of the lookup.
    • Caso contrário, se o conjunto contém apenas os métodos, esse grupo de métodos é o resultado da pesquisa.Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
    • Caso contrário, a pesquisa é ambígua e ocorre um erro em tempo de vinculação.Otherwise, the lookup is ambiguous, and a binding-time error occurs.

Para pesquisas de membro em tipos diferentes de parâmetros de tipo e interfaces e pesquisas de membro em interfaces que são estritamente herança única (tem exatamente zero ou uma interface direta da base de cada interface na cadeia de herança), é o efeito das regras de pesquisa simplesmente que derivado membros ocultar membros base com o mesmo nome ou assinatura.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. Essas pesquisas de herança única nunca são ambíguas.Such single-inheritance lookups are never ambiguous. As ambiguidades que possivelmente podem surgir de pesquisas de membro em interfaces de herança múltipla são descritas em acesso de membro de Interface.The ambiguities that can possibly arise from member lookups in multiple-inheritance interfaces are described in Interface member access.

Tipos baseBase types

Para fins de pesquisa de membro, um tipo T é considerado como tendo os seguintes tipos de base:For purposes of member lookup, a type T is considered to have the following base types:

  • Se T está object, em seguida, T não tem nenhum tipo de base.If T is object, then T has no base type.
  • Se T é um enum_type, os tipos base do T são os tipos de classe System.Enum, System.ValueType, e object.If T is an enum_type, the base types of T are the class types System.Enum, System.ValueType, and object.
  • Se T é um struct_type, os tipos base do T são os tipos de classe System.ValueType e object.If T is a struct_type, the base types of T are the class types System.ValueType and object.
  • Se T é um class_type, os tipos base do T são as classes base T, incluindo o tipo 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.
  • Se T é um interface_type, os tipos base do T são as interfaces base dos T e o tipo 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.
  • Se T é um array_type, os tipos base do T são os tipos de classe System.Array e object.If T is an array_type, the base types of T are the class types System.Array and object.
  • Se T é um delegate_type, os tipos base do T são os tipos de classe System.Delegate e object.If T is a delegate_type, the base types of T are the class types System.Delegate and object.

Membros da funçãoFunction members

Membros da função são membros que contêm instruções executáveis.Function members are members that contain executable statements. Membros da função sempre são membros de tipos e não podem ser membros de namespaces.Function members are always members of types and cannot be members of namespaces. C# define as seguintes categorias de membros da função:C# defines the following categories of function members:

  • MétodosMethods
  • PropriedadesProperties
  • EventosEvents
  • IndexadoresIndexers
  • Operadores definidos pelo usuárioUser-defined operators
  • Construtores de instânciaInstance constructors
  • Construtores estáticosStatic constructors
  • DestruidoresDestructors

Exceto para os destruidores e construtores estáticos (que não podem ser invocados explicitamente), as instruções contidas em membros de função são executadas por meio de invocações de função de membro.Except for destructors and static constructors (which cannot be invoked explicitly), the statements contained in function members are executed through function member invocations. A sintaxe real para a gravação de uma invocação de membro de função depende a categoria de membro de função específica.The actual syntax for writing a function member invocation depends on the particular function member category.

A lista de argumentos (listas de argumentos) de um membro da função chamada fornece os valores reais ou referências de variável para os parâmetros do membro da função.The argument list (Argument lists) of a function member invocation provides actual values or variable references for the parameters of the function member.

As invocações de métodos genéricos podem empregar a inferência de tipo para determinar o conjunto de argumentos de tipo para passar para o método.Invocations of generic methods may employ type inference to determine the set of type arguments to pass to the method. Esse processo é descrito em inferência de tipo.This process is described in Type inference.

As invocações de métodos, indexadores, operadores e construtores de instância empregam a resolução de sobrecarga para determinar quais de um conjunto de candidatos de membros da função para invocar.Invocations of methods, indexers, operators and instance constructors employ overload resolution to determine which of a candidate set of function members to invoke. Esse processo é descrito em resolução de sobrecarga.This process is described in Overload resolution.

Depois que um membro da função específica tiver sido identificado em tempo de associação, possivelmente por meio da resolução de sobrecarga, o processo de tempo de execução real de invocar o membro da função é descrito no verificação de resolução de sobrecarga dinâmicostempodecompilação.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.

A tabela a seguir resume o processamento que ocorre em construções que envolvem as seis categorias de membros da função que podem ser chamados explicitamente.The following table summarizes the processing that takes place in constructs involving the six categories of function members that can be explicitly invoked. Na tabela, e, x, y, e value indicar classificadas como variáveis ou valores, as expressões T indica uma expressão classificada como um tipo, F é o nome simple de um método e P é o nome simple de uma propriedade.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.

ConstruirConstruct ExemploExample DescriçãoDescription
Invocação de métodoMethod invocation F(x,y) Resolução de sobrecarga é aplicada para selecionar o melhor método F na classe ou struct recipiente.Overload resolution is applied to select the best method F in the containing class or struct. O método é invocado com a lista de argumentos (x,y).The method is invoked with the argument list (x,y). Se o método não for static, a expressão de instância é this.If the method is not static, the instance expression is this.
T.F(x,y) Resolução de sobrecarga é aplicada para selecionar o melhor método de F na classe ou struct T.Overload resolution is applied to select the best method F in the class or struct T. Um erro em tempo de vinculação ocorrerá se o método não é static.A binding-time error occurs if the method is not static. O método é invocado com a lista de argumentos (x,y).The method is invoked with the argument list (x,y).
e.F(x,y) Resolução de sobrecarga é aplicada para selecionar o melhor método F na classe, struct ou interface fornecido pelo tipo de e.Overload resolution is applied to select the best method F in the class, struct, or interface given by the type of e. Um erro em tempo de vinculação ocorrerá se o método é static.A binding-time error occurs if the method is static. O método é invocado com a expressão de instância e e a lista de argumentos (x,y).The method is invoked with the instance expression e and the argument list (x,y).
Acesso de propriedadeProperty access P O get acessador da propriedade P na classe ou struct recipiente é invocado.The get accessor of the property P in the containing class or struct is invoked. Ocorrerá um erro de tempo de compilação se P é somente gravação.A compile-time error occurs if P is write-only. Se P não é static, a expressão de instância é this.If P is not static, the instance expression is this.
P = value O set acessador da propriedade P na classe ou struct recipiente é invocado com a lista de argumentos (value).The set accessor of the property P in the containing class or struct is invoked with the argument list (value). Ocorrerá um erro de tempo de compilação se P é somente leitura.A compile-time error occurs if P is read-only. Se P não é static, a expressão de instância é this.If P is not static, the instance expression is this.
T.P O get acessador da propriedade P na classe ou struct T é invocado.The get accessor of the property P in the class or struct T is invoked. Ocorrerá um erro de tempo de compilação se P não é static ou se P é somente gravação.A compile-time error occurs if P is not static or if P is write-only.
T.P = value O set acessador da propriedade P na classe ou struct T é invocado com a lista de argumentos (value).The set accessor of the property P in the class or struct T is invoked with the argument list (value). Ocorrerá um erro de tempo de compilação se P não é static ou se P é somente leitura.A compile-time error occurs if P is not static or if P is read-only.
e.P O get acessador da propriedade P na classe, struct ou interface fornecido pelo tipo de e é invocado com a expressão de instância 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. Um erro em tempo de vinculação ocorrerá se P está static ou se P é somente gravação.A binding-time error occurs if P is static or if P is write-only.
e.P = value O set acessador da propriedade P na classe, struct ou interface fornecido pelo tipo de e é invocado com a expressão de instância e e a lista de argumentos (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). Um erro em tempo de vinculação ocorrerá se P está static ou se P é somente leitura.A binding-time error occurs if P is static or if P is read-only.
Acesso ao eventoEvent access E += value O add acessador do evento E na classe ou struct recipiente é invocado.The add accessor of the event E in the containing class or struct is invoked. Se E é não estático, a expressão de instância é this.If E is not static, the instance expression is this.
E -= value O remove acessador do evento E na classe ou struct recipiente é invocado.The remove accessor of the event E in the containing class or struct is invoked. Se E é não estático, a expressão de instância é this.If E is not static, the instance expression is this.
T.E += value O add acessador do evento E na classe ou struct T é invocado.The add accessor of the event E in the class or struct T is invoked. Ocorrerá um erro de tempo de associação se E não é estático.A binding-time error occurs if E is not static.
T.E -= value O remove acessador do evento E na classe ou struct T é invocado.The remove accessor of the event E in the class or struct T is invoked. Ocorrerá um erro de tempo de associação se E não é estático.A binding-time error occurs if E is not static.
e.E += value O add acessador do evento E na classe, struct ou interface fornecido pelo tipo de e é invocado com a expressão de instância 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. Ocorrerá um erro de tempo de associação se E é estático.A binding-time error occurs if E is static.
e.E -= value O remove acessador do evento E na classe, struct ou interface fornecido pelo tipo de e é invocado com a expressão de instância 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. Ocorrerá um erro de tempo de associação se E é estático.A binding-time error occurs if E is static.
Acesso de indexadorIndexer access e[x,y] Resolução de sobrecarga é aplicada para selecionar o indexador melhor na classe, struct ou interface fornecido pelo tipo de e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. O get acessador do indexador é invocado com a expressão de instância e e a lista de argumentos (x,y).The get accessor of the indexer is invoked with the instance expression e and the argument list (x,y). Um erro em tempo de vinculação ocorrerá se o indexador é somente gravação.A binding-time error occurs if the indexer is write-only.
e[x,y] = value Resolução de sobrecarga é aplicada para selecionar o indexador melhor na classe, struct ou interface fornecido pelo tipo de e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. O set acessador do indexador é invocado com a expressão de instância e e a lista de argumentos (x,y,value).The set accessor of the indexer is invoked with the instance expression e and the argument list (x,y,value). Um erro em tempo de vinculação ocorrerá se o indexador é somente leitura.A binding-time error occurs if the indexer is read-only.
Invocação de operadorOperator invocation -x Resolução de sobrecarga é aplicada para selecionar o operador unário melhor na classe ou struct fornecido pelo tipo de x.Overload resolution is applied to select the best unary operator in the class or struct given by the type of x. O operador selecionado é invocado com a lista de argumentos (x).The selected operator is invoked with the argument list (x).
x + y Resolução de sobrecarga é aplicada para selecionar o operador binário melhor nas classes ou structs fornecido pelos tipos de x e y.Overload resolution is applied to select the best binary operator in the classes or structs given by the types of x and y. O operador selecionado é invocado com a lista de argumentos (x,y).The selected operator is invoked with the argument list (x,y).
Invocação do construtor de instânciaInstance constructor invocation new T(x,y) Resolução de sobrecarga é aplicada para selecionar o melhor construtor de instância na classe ou struct T.Overload resolution is applied to select the best instance constructor in the class or struct T. O construtor de instância é invocado com a lista de argumentos (x,y).The instance constructor is invoked with the argument list (x,y).

Listas de argumentosArgument lists

Cada invocação de membro e o delegado de função inclui uma lista de argumentos que fornece os valores reais ou referências de variável para os parâmetros do membro da função.Every function member and delegate invocation includes an argument list which provides actual values or variable references for the parameters of the function member. A sintaxe para especificar a lista de argumentos de uma invocação de membro de função depende a categoria de membro da função:The syntax for specifying the argument list of a function member invocation depends on the function member category:

  • Por exemplo construtores, métodos, indexadores e delegados, os argumentos são especificados como um argument_list, conforme descrito abaixo.For instance constructors, methods, indexers and delegates, the arguments are specified as an argument_list, as described below. Para indexadores, ao invocar o set acessador, a lista de argumentos Além disso, inclui a expressão especificada como o operando à direita do operador de atribuição.For indexers, when invoking the set accessor, the argument list additionally includes the expression specified as the right operand of the assignment operator.
  • Para propriedades, a lista de argumentos está vazia ao invocar o get acessador e consiste na expressão especificada como o operando à direita do operador de atribuição ao invocar o set acessador.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.
  • Para eventos, a lista de argumentos é formada pela expressão especificada como o operando direito dos += ou -= operador.For events, the argument list consists of the expression specified as the right operand of the += or -= operator.
  • Operadores definidos pelo usuário, a lista de argumentos consiste em único operando do operador unário ou os dois operandos do operador binário.For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator.

Os argumentos de propriedades (propriedades), eventos (eventos) e operadores definidos pelo usuário (operadores) sempre são passados como parâmetros de valor ( Parâmetros de valores).The arguments of properties (Properties), events (Events), and user-defined operators (Operators) are always passed as value parameters (Value parameters). Os argumentos de indexadores (indexadores) sempre são passados como parâmetros de valor (parâmetros de valores) ou matrizes de parâmetros (matrizes de parâmetro).The arguments of indexers (Indexers) are always passed as value parameters (Value parameters) or parameter arrays (Parameter arrays). Não há suporte para parâmetros de referência e de saída para essas categorias de membros da função.Reference and output parameters are not supported for these categories of function members.

Os argumentos de uma invocação de construtor, método, indexador ou delegado de instância são especificados como um 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
    ;

Uma argument_list consiste em um ou mais argumentos, separados por vírgulas.An argument_list consists of one or more arguments, separated by commas. Cada argumento consiste em um recurso opcional argument_name seguido por um argument_value.Each argument consists of an optional argument_name followed by an argument_value. Uma argumento com um argument_name é conhecido como um argumento nomeado, enquanto um argumento sem um argument_name é um argumento posicional.An argument with an argument_name is referred to as a named argument, whereas an argument without an argument_name is a positional argument. É um erro para um argumento posicional aparecer após um argumento nomeado em uma argument_list.It is an error for a positional argument to appear after a named argument in an argument_list.

O argument_value pode assumir um dos seguintes formatos:The argument_value can take one of the following forms:

Parâmetros correspondentesCorresponding parameters

Para cada argumento na lista de argumentos deve ser um parâmetro correspondente no membro da função ou delegado que está sendo invocado.For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.

A lista de parâmetros usada no seguinte é determinada da seguinte maneira:The parameter list used in the following is determined as follows:

  • Para indexadores definidos nas classes e métodos virtuais, a lista de parâmetros separado da declaração mais específica ou substituição do membro da função, começando com o tipo estático do receptor e a pesquisa por meio de suas classes 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.
  • Para métodos de interface e indexadores, a lista de parâmetros é escolhida formam a definição mais específica do membro, começando com o tipo de interface e a pesquisa por meio de interfaces 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. Se nenhuma lista de parâmetro exclusivo é encontrado, uma lista de parâmetros com nomes inacessíveis e sem parâmetros opcionais é construída, para que as invocações não é possível usar parâmetros nomeados ou omitir argumentos opcionais.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.
  • Para métodos parciais, lista de parâmetros de declaração de definição de método parcial é usada.For partial methods, the parameter list of the defining partial method declaration is used.
  • Para todos os outros membros da função e representantes, há apenas uma lista de parâmetro único, que é usada.For all other function members and delegates there is only a single parameter list, which is the one used.

A posição de um argumento ou um parâmetro é definida como o número de argumentos ou parâmetros que precedem-lo na lista de argumentos ou lista de parâmetros.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.

Os parâmetros para argumentos da função membro correspondentes são estabelecidos da seguinte maneira:The corresponding parameters for function member arguments are established as follows:

  • Argumentos de argument_list de construtores de instância, métodos, indexadores e delegados:Arguments in the argument_list of instance constructors, methods, indexers and delegates:
    • Um argumento posicional em que um parâmetro fixado ocorre na mesma posição na lista de parâmetros corresponde a esse parâmetro.A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter.
    • Um argumento posicional de um membro da função com uma matriz de parâmetros invocado em sua forma normal corresponde à matriz de parâmetros, que deve ocorrer na mesma posição na lista de parâmetros.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.
    • Um argumento posicional de um membro da função com uma matriz de parâmetros invocado em sua forma expandida, onde não ocorre a nenhum parâmetro fixo na mesma posição na lista de parâmetros, corresponde a um elemento na matriz de parâmetros.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.
    • Um argumento nomeado corresponde ao parâmetro de mesmo nome na lista de parâmetros.A named argument corresponds to the parameter of the same name in the parameter list.
    • Para indexadores, ao invocar o set acessador, a expressão especificada como o operando à direita do operador de atribuição corresponde ao implícito value parâmetro do set declaração do acessador.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.
  • Para propriedades, ao invocar o get acessador lá estão sem argumentos.For properties, when invoking the get accessor there are no arguments. Ao invocar o set acessador, a expressão especificada como o operando à direita do operador de atribuição corresponde ao implícito value parâmetro do set declaração do acessador.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.
  • Operadores de unário definido pelo usuário (incluindo conversões), o único operando corresponde ao parâmetro único da declaração do operador.For user-defined unary operators (including conversions), the single operand corresponds to the single parameter of the operator declaration.
  • Operadores binários definidos pelo usuário, o operando esquerdo corresponde ao primeiro parâmetro e o operando direito corresponde ao segundo parâmetro da declaração do operador.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.

Avaliação do tempo de execução das listas de argumentosRun-time evaluation of argument lists

Durante o processamento de tempo de execução de uma invocação de membro de função (verificação de resolução de sobrecarga de dinâmica de tempo de compilação), as expressões ou referências de variável de uma lista de argumentos são avaliadas em ordem, da esquerda para a direita, como a seguir: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:

  • Para um parâmetro de valor, a expressão de argumento é avaliada e uma conversão implícita (conversões implícitas) para o parâmetro correspondente tipo é executado.For a value parameter, the argument expression is evaluated and an implicit conversion (Implicit conversions) to the corresponding parameter type is performed. O valor resultante se torna o valor inicial do parâmetro value na invocação de membro da função.The resulting value becomes the initial value of the value parameter in the function member invocation.
  • Para um parâmetro de referência ou de saída, a referência de variável é avaliada e o local de armazenamento resultante se torna o local de armazenamento, representado pelo parâmetro na invocação de membro da função.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. Se a referência de variável fornecida como um referência ou parâmetro de saída é um elemento de matriz de um reference_type, é realizada uma verificação de tempo de execução para garantir que o tipo de elemento da matriz é idêntico ao tipo do parâmetro.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. Se essa verificação falha, um System.ArrayTypeMismatchException é gerada.If this check fails, a System.ArrayTypeMismatchException is thrown.

Métodos, indexadores e construtores de instância podem declarar o parâmetro mais à direita como uma matriz de parâmetro (matrizes de parâmetro).Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array (Parameter arrays). Esses membros de função são invocados em sua forma normal ou em seus formulários expandidos, dependendo do que é aplicável (membro da função aplicável):Such function members are invoked either in their normal form or in their expanded form depending on which is applicable (Applicable function member):

  • Quando um membro de função com uma matriz de parâmetros é invocado em sua forma normal, o argumento fornecido para a matriz de parâmetros deve ser uma única expressão que é implicitamente conversível (conversões implícitas) para o tipo de matriz de parâmetro.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. Nesse caso, a matriz de parâmetro Age exatamente como um parâmetro de valor.In this case, the parameter array acts precisely like a value parameter.
  • Quando um membro de função com uma matriz de parâmetros é invocado em sua forma expandida, a invocação deve especificar zero ou mais argumentos posicionais para a matriz de parâmetros, onde cada argumento é uma expressão que é implicitamente conversível (implícitas conversões) para o tipo de elemento da matriz de parâmetros.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. Nesse caso, a invocação cria uma instância do tipo de parâmetro de matriz com um comprimento correspondente ao número de argumentos, inicializa os elementos da instância de matriz com os valores de argumento fornecido e usa a instância de matriz recém-criado como o real argumento.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.

As expressões de uma lista de argumentos sempre são avaliadas na ordem em que elas são gravadas.The expressions of an argument list are always evaluated in the order they are written. Portanto, o exemploThus, 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++);
    }
}

produz a saídaproduces the output

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

As regras de variação conjunta de matriz (covariância de matriz) permite um valor de um tipo de matriz A[] seja uma referência a uma instância de um tipo de matriz B[], desde que existe uma conversão de referência implícita de B para 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. Devido a essas regras, quando um elemento de matriz de um reference_type é passado como um parâmetro de saída ou de referência, uma verificação de tempo de execução é necessária para garantir que o tipo de elemento real da matriz é idêntico do parâmetro.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. No exemploIn 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
    }
}

a segunda chamada de F faz com que um System.ArrayTypeMismatchException seja lançada porque o tipo de elemento real do b é string e não 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.

Quando um membro de função com uma matriz de parâmetros é invocado em sua forma expandida, a invocação é processada exatamente como se uma expressão de criação de matriz com um inicializador de matriz (expressões de criação de matriz) foi inserido em torno de parâmetros expandidos.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. Por exemplo, dada a declaraçãoFor example, given the declaration

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

as seguintes invocações da forma expandida do métodothe following invocations of the expanded form of the method

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

corresponder exatamente àcorrespond exactly to

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

Em particular, observe que uma matriz vazia é criada quando há zero argumentos fornecidos para a matriz de parâmetros.In particular, note that an empty array is created when there are zero arguments given for the parameter array.

Quando os argumentos forem omitidos de um membro da função com parâmetros opcionais correspondentes, os argumentos padrão da declaração de membro da função são passados implicitamente.When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. Porque eles sempre são constantes, sua avaliação não afetará a ordem de avaliação dos argumentos restantes.Because these are always constant, their evaluation will not impact the evaluation order of the remaining arguments.

Inferência de tipoType inference

Quando um método genérico é chamado sem especificar argumentos de tipo, uma inferência de tipo processo tenta inferir argumentos de tipo para a chamada.When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. A presença de inferência de tipo permite uma sintaxe mais conveniente a ser usado para chamar um método genérico e permite ao programador Evite especificar informações de tipo redundantes.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. Por exemplo, dada a declaração de método: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;
    }
}

é possível invocar o Choose método sem especificar explicitamente um argumento de tipo: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>

Por meio de inferência de tipo, os argumentos de tipo int e string são determinados dos argumentos para o método.Through type inference, the type arguments int and string are determined from the arguments to the method.

Inferência de tipo ocorre como parte do processamento de tempo de associação de uma invocação de método (invocações de método) e ocorre antes da etapa de resolução de sobrecarga da invocação.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. Quando um grupo de método em particular for especificado em uma invocação de método e nenhum argumento de tipo é especificado como parte da invocação do método, a inferência de tipos é aplicada a cada método genérico no grupo de método.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. Se a inferência de tipo for bem-sucedida, os argumentos de tipo inferidos são usados para determinar os tipos de argumentos para a resolução de sobrecarga subsequentes.If type inference succeeds, then the inferred type arguments are used to determine the types of arguments for subsequent overload resolution. Se a resolução de sobrecarga escolhe um método genérico que o usado para invocar, os argumentos de tipo inferidos são usados como os argumentos de tipo real para a invocação.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. Se a falha de inferência de tipo para um método específico, esse método não participará na resolução de sobrecarga.If type inference for a particular method fails, that method does not participate in overload resolution. A falha de inferência de tipo, por si só, não causa um erro em tempo de vinculação.The failure of type inference, in and of itself, does not cause a binding-time error. No entanto, isso geralmente leva a um erro em tempo de vinculação quando a resolução de sobrecarga, em seguida, consegue encontrar nenhum método aplicável.However, it often leads to a binding-time error when overload resolution then fails to find any applicable methods.

Se o número fornecido de argumentos é diferente do número de parâmetros no método, em seguida, inferência imediatamente falhará.If the supplied number of arguments is different than the number of parameters in the method, then inference immediately fails. Caso contrário, suponha que o método genérico tem a seguinte assinatura:Otherwise, assume that the generic method has the following signature:

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

Com uma chamada de método do formulário M(E1...Em) a tarefa de inferência de tipo é encontrar os argumentos de tipo exclusivo S1...Sn para cada um dos parâmetros de tipo X1...Xn para que a chamada M<S1...Sn>(E1...Em) se torna válido.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.

Durante o processo de inferência de cada parâmetro de tipo Xi seja fixo a um determinado tipo Si ou unfixed com um conjunto associado de limites.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. Cada um dos limites é algum tipo T.Each of the bounds is some type T. Inicialmente, cada variável de tipo Xi é unfixed com um conjunto vazio de limites.Initially each type variable Xi is unfixed with an empty set of bounds.

Inferência de tipos ocorre em fases.Type inference takes place in phases. Cada fase tentará inferir argumentos de tipo para obter mais variáveis de tipo com base nas descobertas da fase anterior.Each phase will try to infer type arguments for more type variables based on the findings of the previous phase. A primeira fase faz algumas inferências inicias dos limites, enquanto a segunda fase variáveis de tipo para tipos específicos de correções e infere o dos limites.The first phase makes some initial inferences of bounds, whereas the second phase fixes type variables to specific types and infers further bounds. A segunda fase pode ter que ser repetido um número de vezes.The second phase may have to be repeated a number of times.

Observação: Tipo inferência ocorre não apenas quando um método genérico é chamado.Note: Type inference takes place not only when a generic method is called. Inferência de tipo para conversão de grupos de método é descrita em inferência de tipos para a conversão de grupos de métodos e encontrar o melhor tipo comum de um conjunto de expressões é descrita em localizando o melhor tipo comum de um conjunto expressões.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.

A primeira faseThe first phase

Para cada um dos argumentos de método Ei:For each of the method arguments Ei:

  • Se Ei é uma função anônima, uma inferência de tipo de parâmetro explícito (inferências de tipo de parâmetro explícito) é feita do Ei para TiIf Ei is an anonymous function, an explicit parameter type inference (Explicit parameter type inferences) is made from Ei to Ti
  • Caso contrário, se Ei tem um tipo U e xi é um parâmetro de valor, uma inferência de tipos de limite inferior é feita do U para 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.
  • Caso contrário, se Ei tem um tipo U e xi é uma ref ou out parâmetro, uma exato inferência é feita 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.
  • Caso contrário, nenhuma inferência é feita para esse argumento.Otherwise, no inference is made for this argument.

A segunda faseThe second phase

A segunda fase procede da seguinte maneira:The second phase proceeds as follows:

  • Todos os unfixed variáveis do tipo Xi quais não dependem (dependência) qualquer Xj são fixos (corrigindo).All unfixed type variables Xi which do not depend on (Dependence) any Xj are fixed (Fixing).
  • Se essas variáveis de tipo não existir, todos os unfixed variáveis do tipo Xi são fixa para o qual todos os itens a seguir manter:If no such type variables exist, all unfixed type variables Xi are fixed for which all of the following hold:
    • Há pelo menos uma variável de tipo Xj depende do que XiThere is at least one type variable Xj that depends on Xi
    • Xi tem um conjunto não vazio de limitesXi has a non-empty set of bounds
  • Se essas variáveis de tipo não existem e ainda houver unfixed variáveis do tipo, falha de inferência de tipo.If no such type variables exist and there are still unfixed type variables, type inference fails.
  • Caso contrário, se nenhuma outra unfixed as variáveis de tipo existem, inferência de tipo é bem-sucedida.Otherwise, if no further unfixed type variables exist, type inference succeeds.
  • Caso contrário, para todos os argumentos Ei com o tipo de parâmetro correspondente Ti em que o tipos de saída (tipos de saída) contêm unfixed variáveis do tipo Xj , mas o tipos de entrada (tipos de entrada) não fizer isso, uma inferência de tipo de saída (inferências de tipo de saída ) é feita partir Ei para 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. Em seguida, a segunda fase é repetida.Then the second phase is repeated.

Tipos de entradaInput types

Se E é um grupo de método ou função anônima de tipo implícito e T é um delegado, tipo ou tipo de árvore de expressão e todos os tipos de parâmetro T são tipos de entrada de E com tipo 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.

Tipos de saídaOutput types

Se E é um grupo de método ou uma função anônima e T é um delegado, tipo ou tipo de árvore de expressão e o tipo de retorno T é uma tipo de saída E com tipo 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.

DependênciaDependence

Uma unfixed variável de tipo Xi depende diretamente uma variável do tipo unfixed Xj se algum argumento Ek com tipo Tk Xj ocorre em um tipo de entrada de Ek com tipo Tk e Xi ocorre em um tipo de saída de Ek com tipo Tk.An unfixed type variable Xi depends directly on an unfixed type variable Xj if for some argument Ek with type Tk Xj occurs in an input type of Ek with type Tk and Xi occurs in an output type of Ek with type Tk.

Xj depende Xi se Xj depende diretamente Xi ou se Xi depende diretamente Xk e Xk depende Xj.Xj depends on Xi if Xj depends directly on Xi or if Xi depends directly on Xk and Xk depends on Xj. Portanto, "depende" é o fechamento transitivo, mas não reflexivo de "depende diretamente".Thus "depends on" is the transitive but not reflexive closure of "depends directly on".

Inferências de tipo de saídaOutput type inferences

Uma inferência de tipo de saída é feita partir uma expressão E para um tipo T da seguinte maneira:An output type inference is made from an expression E to a type T in the following way:

  • Se E é uma função anônima com o tipo de retorno deduzido U (tipo de retorno inferido) e T é um tipo de delegado ou tipo de árvore de expressão com o tipo de retorno Tb, em seguida, um inferência de tipos de limite inferior (inferências de limite inferior) é feita do U para Tb.If E is an anonymous function with inferred return type U (Inferred return type) and T is a delegate type or expression tree type with return type Tb, then a lower-bound inference (Lower-bound inferences) is made from U to Tb.
  • Caso contrário, se E é um grupo de método e T é um tipo de delegado ou tipo de árvore de expressão com tipos de parâmetro T1...Tk e o tipo de retorno Tbe a resolução de sobrecarga de E com os tipos de T1...Tk produz um um único método com o tipo de retorno U, em seguida, um inferência de tipos de limite inferior é feita da U para Tb.Otherwise, if E is a method group and T is a delegate type or expression tree type with parameter types T1...Tk and return type Tb, and overload resolution of E with the types T1...Tk yields a single method with return type U, then a lower-bound inference is made from U to Tb.
  • Caso contrário, se E é uma expressão com o tipo U, em seguida, um inferência de tipos de limite inferior é feita do U para T.Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T.
  • Caso contrário, nenhum inferências são feitas.Otherwise, no inferences are made.

Inferências de tipo de parâmetro explícitoExplicit parameter type inferences

Uma inferência de tipo de parâmetro explícito é feita partir uma expressão E para um tipo T da seguinte maneira:An explicit parameter type inference is made from an expression E to a type T in the following way:

  • Se E é uma função anônima digitada explicitamente com tipos de parâmetro U1...Uk e T é um tipo de delegado ou tipo de árvore de expressão com tipos de parâmetro V1...Vk , em seguida, para cada Ui um exata inferência (exato inferências) é feita da Ui para correspondente Vi.If E is an explicitly typed anonymous function with parameter types U1...Uk and T is a delegate type or expression tree type with parameter types V1...Vk then for each Ui an exact inference (Exact inferences) is made from Ui to the corresponding Vi.

Inferências exatasExact inferences

Uma exato inferência de um tipo U para um tipo V é feita da seguinte maneira:An exact inference from a type U to a type V is made as follows:

  • Se V é um dos unfixed Xi , em seguida, U é adicionado ao conjunto de limites exatos para Xi.If V is one of the unfixed Xi then U is added to the set of exact bounds for Xi.

  • Caso contrário, define V1...Vk e U1...Uk são determinadas pela verificação se qualquer um dos casos a seguir se aplicam:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • V é um tipo de matriz V1[...] e U é um tipo de matriz U1[...] da mesma classificaçãoV is an array type V1[...] and U is an array type U1[...] of the same rank
    • V é o tipo V1? e U é do tipo U1?V is the type V1? and U is the type U1?
    • V é um tipo construído C<V1...Vk>e U é um tipo construído C<U1...Uk>V is a constructed type C<V1...Vk>and U is a constructed type C<U1...Uk>

    Se qualquer um desses casos, em seguida, aplicar um exato inferência é feita de cada Ui para correspondente Vi.If any of these cases apply then an exact inference is made from each Ui to the corresponding Vi.

  • Caso contrário, nenhum inferências são feitas.Otherwise no inferences are made.

Limite inferior inferênciasLower-bound inferences

Um inferência de tipos de limite inferior partir um tipo U para um tipo V é feita da seguinte maneira:A lower-bound inference from a type U to a type V is made as follows:

  • Se V é um dos unfixed Xi , em seguida, U é adicionado ao conjunto de limites inferiores do Xi.If V is one of the unfixed Xi then U is added to the set of lower bounds for Xi.

  • Caso contrário, se V é o tipo V1?e U é o tipo U1? uma inferência de limite inferior é feita da U1 para 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.

  • Caso contrário, define U1...Uk e V1...Vk são determinadas pela verificação se qualquer um dos casos a seguir se aplicam:Otherwise, sets U1...Uk and V1...Vk are determined by checking if any of the following cases apply:

    • V é um tipo de matriz V1[...] e U é um tipo de matriz U1[...] (ou um parâmetro de tipo cujo tipo base eficaz é U1[...]) da mesma classificaçãoV 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 é um dos IEnumerable<V1>, ICollection<V1> ou IList<V1> e U é um tipo de matriz unidimensional U1[](ou um parâmetro de tipo cujo tipo base eficaz é 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 é um tipo de classe, struct, interface ou delegado construído C<V1...Vk> e há um tipo exclusivo C<U1...Uk> , de modo que U (ou, se U é um parâmetro de tipo, sua classe base efetivo ou qualquer membro do seu conjunto efetivo de interface) é idêntico ao, herda (direta ou indiretamente) ou implementa (direta ou indiretamente) 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>.

      (A restrição "exclusividade" significa que, na interface do case C<T> {} class U: C<X>, C<Y> {}, nenhuma inferência é feita quando a inferência de U à C<T> porque U1 poderia ser 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.)

    Se qualquer um desses casos aplicar uma inferência é feita partir cada Ui para correspondente Vi da seguinte maneira:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Se Ui não é conhecido como um tipo de referência, uma exato inferência é feitaIf Ui is not known to be a reference type then an exact inference is made
    • Caso contrário, se U é um tipo de matriz, um inferência de tipos de limite inferior é feitaOtherwise, if U is an array type then a lower-bound inference is made
    • Caso contrário, se V está C<V1...Vk> e em seguida, depende de inferência de tipos no parâmetro de tipo i-th C:Otherwise, if V is C<V1...Vk> then inference depends on the i-th type parameter of C:
      • Se ele é covariante, uma inferência de tipos de limite inferior é feita.If it is covariant then a lower-bound inference is made.
      • Se ele é contravariante, então um inferência de tipos de limite superior é feita.If it is contravariant then an upper-bound inference is made.
      • Se ele for invariável, uma exato inferência é feita.If it is invariant then an exact inference is made.
  • Caso contrário, nenhum inferências são feitas.Otherwise, no inferences are made.

Limite superior inferênciasUpper-bound inferences

Uma inferência de tipos de limite superior de um tipo U para um tipo V é feita da seguinte maneira:An upper-bound inference from a type U to a type V is made as follows:

  • Se V é um dos unfixed Xi , em seguida, U é adicionado ao conjunto de limites superiores do Xi.If V is one of the unfixed Xi then U is added to the set of upper bounds for Xi.

  • Caso contrário, define V1...Vk e U1...Uk são determinadas pela verificação se qualquer um dos casos a seguir se aplicam:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • U é um tipo de matriz U1[...] e V é um tipo de matriz V1[...] da mesma classificaçãoU is an array type U1[...] and V is an array type V1[...] of the same rank

    • U é um dos IEnumerable<Ue>, ICollection<Ue> ou IList<Ue> e V é um tipo de matriz unidimensional Ve[]U is one of IEnumerable<Ue>, ICollection<Ue> or IList<Ue> and V is a one-dimensional array type Ve[]

    • U é o tipo U1? e V é do tipo V1?U is the type U1? and V is the type V1?

    • U é construído de classe, struct, tipo de interface ou delegado C<U1...Uk> e V é uma classe, struct, tipo de delegado ou interface que é idêntico a herda (direta ou indiretamente) ou implementa (direta ou indiretamente) um tipo exclusivo 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>

      (A restrição "exclusividade" significa que, se tivermos interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}, nenhuma inferência é feita quando a inferência de C<U1> para 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>. Inferências não são feitas de U1 para um X<Q> ou Y<Q>.)Inferences are not made from U1 to either X<Q> or Y<Q>.)

    Se qualquer um desses casos aplicar uma inferência é feita partir cada Ui para correspondente Vi da seguinte maneira:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Se Ui não é conhecido como um tipo de referência, uma exato inferência é feitaIf Ui is not known to be a reference type then an exact inference is made
    • Caso contrário, se V é um tipo de matriz, uma inferência de tipos de limite superior é feitaOtherwise, if V is an array type then an upper-bound inference is made
    • Caso contrário, se U está C<U1...Uk> e em seguida, depende de inferência de tipos no parâmetro de tipo i-th C:Otherwise, if U is C<U1...Uk> then inference depends on the i-th type parameter of C:
      • Se ele é covariante, uma inferência de tipos de limite superior é feita.If it is covariant then an upper-bound inference is made.
      • Se ele é contravariante, em seguida, um inferência de tipos de limite inferior é feita.If it is contravariant then a lower-bound inference is made.
      • Se ele for invariável, uma exato inferência é feita.If it is invariant then an exact inference is made.
  • Caso contrário, nenhum inferências são feitas.Otherwise, no inferences are made.

CorrigirFixing

Uma unfixed variável de tipo Xi com um conjunto de limites é fixa da seguinte maneira:An unfixed type variable Xi with a set of bounds is fixed as follows:

  • O conjunto de tipos de candidatos Uj começa como o conjunto de todos os tipos no conjunto de limites para Xi.The set of candidate types Uj starts out as the set of all types in the set of bounds for Xi.
  • Em seguida, examinaremos cada limite para Xi por sua vez: Para cada limite exata U de Xi todos os tipos Uj que não são idêntico ao U são removidas do conjunto de candidatas.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. Cada limite inferior U dos Xi todos os tipos Uj para o qual existe é não uma conversão implícita de U são removidas do conjunto de candidatas.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. Para cada limite superior U de Xi todos os tipos Uj daí que está não uma conversão implícita para U são removidas do conjunto de candidatos.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.
  • Se entre os demais tipos de candidato Uj há um tipo exclusivo V de que há uma conversão implícita para todos os outros candidatos tipos, em seguida, Xi está fixado em 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.
  • Caso contrário, a inferência de tipo falhará.Otherwise, type inference fails.

Tipo de retorno deduzidoInferred return type

O inferido do tipo de retorno de uma função anônima F é usado durante a resolução de sobrecarga e de inferência de tipo.The inferred return type of an anonymous function F is used during type inference and overload resolution. O tipo de retorno deduzido só pode ser determinado para uma função anônima onde o parâmetro todos os tipos são conhecidos, ou porque eles são atribuídos explicitamente, fornecido por meio de uma conversão de função anônima ou inferido durante a inferência de tipo em um delimitador genérica invocação de método.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.

O inferido do tipo de resultado é determinado da seguinte maneira:The inferred result type is determined as follows:

  • Se o corpo da F é um expressão que tem um tipo e, em seguida, o tipo inferido do resultado de F é o tipo dessa expressão.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.
  • Se o corpo da F é um bloco e o conjunto de expressões no bloco de return instruções tem um tipo comum melhor T (localizando o melhor tipo comum de um conjunto de expressões), em seguida, o tipo de resultado inferido de F é T.If the body of F is a block and the set of expressions in the block's return statements has a best common type T (Finding the best common type of a set of expressions), then the inferred result type of F is T.
  • Caso contrário, um tipo de resultado não pode ser inferido para F.Otherwise, a result type cannot be inferred for F.

O inferido do tipo de retorno é determinado da seguinte maneira:The inferred return type is determined as follows:

  • Se F é assíncrono e o corpo da F é uma expressão classificada como nada (classificações de expressão), ou um bloco de instruções onde não há instruções return têm expressões, é do tipo de retorno inferido 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
  • Se F é assíncrono e tem um tipo de resultado inferido T, é do tipo de retorno inferido 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>.
  • Se F é não assíncronas e tem um tipo de resultado inferido T, é do tipo de retorno inferido T.If F is non-async and has an inferred result type T, the inferred return type is T.
  • Caso contrário, um tipo de retorno não pode ser inferido para F.Otherwise a return type cannot be inferred for F.

Como um exemplo de inferência de tipo que envolvem funções anônimas, considere a Select método de extensão declarados no System.Linq.Enumerable classe: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);
        }
    }
}

Supondo que o System.Linq namespace foi importado com um using cláusula e dada a classe Customer com um Name propriedade do tipo string, o Select método pode ser usado para selecionar os nomes de uma lista de clientes: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);

A invocação de método de extensão (invocações de método de extensão) de Select é processada por reescrever a chamada para uma invocação de método estático: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);

Como argumentos de tipo não foram especificados explicitamente, a inferência de tipo é usada para inferir os argumentos de tipo.Since type arguments were not explicitly specified, type inference is used to infer the type arguments. Primeiro, o customers argumento está relacionado à source parâmetro, inferir T ser Customer.First, the customers argument is related to the source parameter, inferring T to be Customer. Em seguida, usando a função anônima digite descrito acima, do processo de inferência c recebe o tipo Customere a expressão c.Name está relacionado ao tipo de retorno dos selector parâmetro, inferindo S ser 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. Portanto, a invocação é equivalente aThus, the invocation is equivalent to

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

e o resultado é do tipo IEnumerable<string>.and the result is of type IEnumerable<string>.

O exemplo a seguir demonstra o tipo de função anônima como inferência de tipos permite que as informações de tipo "fluir" entre os argumentos em uma invocação de método genérico.The following example demonstrates how anonymous function type inference allows type information to "flow" between arguments in a generic method invocation. Com o método:Given the method:

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

Inferência de tipo para a invocação:Type inference for the invocation:

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

procede da seguinte maneira: Primeiro, o argumento "1:15:30" está relacionado à value parâmetro, inferir X ser string.proceeds as follows: First, the argument "1:15:30" is related to the value parameter, inferring X to be string. Então, o parâmetro da primeira função anônima s, recebe o tipo inferido stringe a expressão TimeSpan.Parse(s) está relacionado ao tipo de retorno de f1, inferindo Y ser 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. Por fim, o parâmetro da segunda função anônima, t, recebe o tipo inferido System.TimeSpane a expressão t.TotalSeconds está relacionado ao tipo de retorno de f2, inferindo Z ser 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. Portanto, o resultado da invocação é do tipo double.Thus, the result of the invocation is of type double.

Inferência de tipo para conversão de grupos de métodoType inference for conversion of method groups

Semelhante às chamadas de métodos genéricos, inferência de tipo também deve ser aplicada quando um grupo de métodos M que contém um método genérico é convertido em um tipo de delegado fornecidos D (conversões de grupo de método).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). Um métodoGiven a method

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

e o grupo de métodos M que está sendo atribuído ao tipo de delegado D a tarefa de inferência de tipo é encontrar os argumentos de tipo S1...Sn , de modo que a expressão: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>

se torna compatível (declarações de delegado) com D.becomes compatible (Delegate declarations) with D.

Diferente do algoritmo de inferência de tipo para chamadas de método genérico, nesse caso, há apenas o argumento tipos, nenhum argumento expressões.Unlike the type inference algorithm for generic method calls, in this case there are only argument types, no argument expressions. Em particular, não há nenhuma função anônima e, portanto, sem a necessidade de várias fases de inferência de tipos.In particular, there are no anonymous functions and hence no need for multiple phases of inference.

Em vez disso, todos os Xi são considerados unfixede uma inferência de tipos de limite inferior é feita do cada tipo de argumento Uj de D à o tipo de parâmetro correspondente 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. Se qualquer uma da Xi não há limites foram encontrados, falha de inferência de tipo.If for any of the Xi no bounds were found, type inference fails. Caso contrário, todos os Xi estão fixo correspondente Si, que são o resultado de inferência de tipo.Otherwise, all Xi are fixed to corresponding Si, which are the result of type inference.

Localizando o melhor tipo comum de um conjunto de expressõesFinding the best common type of a set of expressions

Em alguns casos, um tipo comum deve ser deduzida para um conjunto de expressões.In some cases, a common type needs to be inferred for a set of expressions. Em particular, os tipos de elementos de matrizes de tipo implícito e os tipos de retorno de funções anônimas com bloco corpos encontram-se dessa maneira.In particular, the element types of implicitly typed arrays and the return types of anonymous functions with block bodies are found in this way.

Intuitivamente, dado um conjunto de expressões E1...Em essa inferência de tipos deve ser equivalente a chamar um métodoIntuitively, given a set of expressions E1...Em this inference should be equivalent to calling a method

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

com o Ei como argumentos.with the Ei as arguments.

Mais precisamente, a inferência começa com um unfixed variável de tipo X.More precisely, the inference starts out with an unfixed type variable X. Inferências de tipo de saída , em seguida, são feitas partir cada Ei para X.Output type inferences are then made from each Ei to X. Por fim, X está fixo e, se for bem-sucedido, resultante de tipo S é o melhor tipo comum resultante para as expressões.Finally, X is fixed and, if successful, the resulting type S is the resulting best common type for the expressions. Se nenhum S existir, as expressões não têm nenhum tipo comum melhor.If no such S exists, the expressions have no best common type.

Resolução de sobrecargaOverload resolution

Resolução de sobrecarga é um mecanismo de tempo de associação para selecionar o membro da função melhor invocar dada uma lista de argumentos e um conjunto de membros da função de candidato.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. Resolução de sobrecarga seleciona o membro da função para invocar nos seguintes contextos distintos em c#:Overload resolution selects the function member to invoke in the following distinct contexts within C#:

Cada um desses contextos define o conjunto de membros da função release candidate e a lista de argumentos em sua própria maneira exclusiva, conforme descrito em detalhes nas seções listados acima.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. Por exemplo, o conjunto de candidatos para uma invocação de método não inclui métodos marcados override (pesquisa de membro), e métodos em uma classe base não são candidatos se qualquer método em uma classe derivada é aplicável ( As invocações de método).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).

Depois que foram identificados os membros da função release candidate e a lista de argumentos, a seleção do membro da função recomendada é a mesma em todos os casos: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:

  • Dado o conjunto de membros da função candidato aplicável, a melhor função membro nesse conjunto é localizado.Given the set of applicable candidate function members, the best function member in that set is located. Se o conjunto contém apenas um membro da função, esse membro da função é o membro da função melhor.If the set contains only one function member, then that function member is the best function member. Caso contrário, o membro da função melhor será o membro de uma função que é melhor do que todos os outros membros da função em relação à lista de argumento fornecido, desde que cada membro da função é comparado com todos os outros membros da função usando as regras em Membro de função melhor.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. Se não houver exatamente um membro da função que é melhor do que todos os outros membros da função, em seguida, a invocação de membro da função é ambígua e ocorre um erro em tempo de vinculação.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.

As seções a seguir definem o significado exato dos termos membro da função aplicáveis e melhor membro da função.The following sections define the exact meanings of the terms applicable function member and better function member.

Membro de função aplicáveisApplicable function member

Um membro da função deve ser um membro da função aplicáveis em relação a uma lista de argumentos A quando todos os itens a seguir forem verdadeiras: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:

  • Cada argumento na A corresponde a um parâmetro na declaração de membro da função, conforme descrito em correspondente parâmetros, e qualquer parâmetro não correspondente ao nenhum argumento é um parâmetro opcional.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.
  • Para cada argumento na A, o modo do argumento de passagem de parâmetro (ou seja, valor, ref, ou out) é idêntico para o modo de passagem de parâmetro do parâmetro correspondente, eFor 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
    • para um parâmetro de valor ou uma matriz de parâmetros, uma conversão implícita (conversões implícitas) existe do argumento para o tipo do parâmetro correspondente, 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
    • para um ref ou out parâmetro, o tipo do argumento é idêntico ao tipo do parâmetro correspondente.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter. Afinal de contas, uma ref ou out parâmetro é um alias para o argumento passado.After all, a ref or out parameter is an alias for the argument passed.

Para um membro da função que inclui uma matriz de parâmetros, se o membro da função for aplicável, as regras acima, ele deve ser aplicável em sua forma normal.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. Se um membro da função que inclui uma matriz de parâmetro não for aplicável em sua forma normal, o membro da função em vez disso, pode ser aplicável em sua expandido formulário: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:

  • A forma expandida é construída, substituindo a matriz de parâmetros na declaração de membro da função com zero ou mais parâmetros de valor do tipo de elemento do parâmetro de matriz, que o número de argumentos na lista de argumentos A corresponde ao total número de parâmetros.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. Se A tem menos argumentos que o número de parâmetros fixos na declaração de membro da função, a forma expandida do membro da função não pode ser construída e, portanto, não é aplicável.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.
  • Caso contrário, a forma expandida é aplicável se cada argumento na A o modo de passagem de parâmetro do argumento é idêntico para o modo de passagem de parâmetro do parâmetro correspondente, eOtherwise, 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
    • para um parâmetro de valor fixo ou criados pela expansão, uma conversão implícita de um parâmetro de valor (conversões implícitas) existe do tipo do argumento para o tipo do parâmetro correspondente, 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
    • para um ref ou out parâmetro, o tipo do argumento é idêntico ao tipo do parâmetro correspondente.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter.

Membro de função melhorBetter function member

A fim de determinar o membro da função melhor, uma lista de argumentos simplificada um é construída que contém apenas as expressões do argumento em si na ordem em que eles aparecem na lista de argumentos original.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.

Listas de parâmetros para cada função candidato membros são construídos da seguinte maneira:Parameter lists for each of the candidate function members are constructed in the following way:

  • A forma expandida será usada se o membro da função foi aplicável apenas a forma expandida.The expanded form is used if the function member was applicable only in the expanded form.
  • Parâmetros opcionais sem argumentos correspondentes são removidos da lista de parâmetrosOptional parameters with no corresponding arguments are removed from the parameter list
  • Os parâmetros são reordenados para que eles ocorram na mesma posição como o argumento correspondente na lista de argumentos.The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.

Dada uma lista de argumentos A com um conjunto de expressões de argumento {E1, E2, ..., En} e dois membros da função aplicável Mp e Mq com tipos de parâmetro {P1, P2, ..., Pn} e {Q1, Q2, ..., Qn}, Mp é definido como um melhor membro da função que Mq seGiven 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

  • para cada argumento, a conversão implícita da Ex à Qx não é melhor do que a conversão implícita de Ex para Px, efor each argument, the implicit conversion from Ex to Qx is not better than the implicit conversion from Ex to Px, and
  • para pelo menos um argumento, a conversão de Ex à Px é melhor do que a conversão de Ex para Qx.for at least one argument, the conversion from Ex to Px is better than the conversion from Ex to Qx.

Ao fazer isso, se Mp ou Mq é aplicável em sua forma expandida, em seguida, Px ou Qx refere-se a um parâmetro no formato expandido da lista de parâmetros.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.

Caso o parâmetro de tipo sequências {P1, P2, ..., Pn} e {Q1, Q2, ..., Qn} são equivalentes (ou seja, cada Pi tem uma conversão de identidade para os respectivos Qi), as seguintes regras de desempate são aplicadas em ordem, para determinar o melhor membro de função.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.

  • Se Mp é um método não genérico e Mq é um método genérico, em seguida, Mp é melhor do que Mq.If Mp is a non-generic method and Mq is a generic method, then Mp is better than Mq.
  • Caso contrário, se Mp é aplicável em sua forma normal e Mq tem um params de matriz e é aplicável apenas em sua forma expandida, em seguida, Mp é melhor do que 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.
  • Caso contrário, se Mp mais declarou parâmetros que Mq, em seguida, Mp é melhor do que Mq.Otherwise, if Mp has more declared parameters than Mq, then Mp is better than Mq. Isso pode ocorrer se os dois métodos têm params matrizes e são aplicável apenas em seus formulários expandidos.This can occur if both methods have params arrays and are applicable only in their expanded forms.
  • Caso contrário se todos os parâmetros de Mp tem um argumento correspondente, enquanto os argumentos padrão precisam ser substituídos pelo menos um parâmetro opcional nas Mq , em seguida, Mp é melhor do que 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.
  • Caso contrário, se Mp tem tipos de parâmetro mais específicos que Mq, em seguida, Mp é melhor do que Mq.Otherwise, if Mp has more specific parameter types than Mq, then Mp is better than Mq. Deixe {R1, R2, ..., Rn} e {S1, S2, ..., Sn} representam os tipos de parâmetro não instanciado e não expandidas de Mp e Mq.Let {R1, R2, ..., Rn} and {S1, S2, ..., Sn} represent the uninstantiated and unexpanded parameter types of Mp and Mq. Mpdo tipos de parâmetro são mais específicos que Mqdo se, para cada parâmetro, Rx não é menos específicas Sxe, pelo menos um parâmetro, Rx é mais específico 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:
    • Um parâmetro de tipo é menos específico um parâmetro sem tipo.A type parameter is less specific than a non-type parameter.
    • Recursivamente, um tipo construído é mais específico do que outro tipo construído (com o mesmo número de argumentos de tipo) se pelo menos um argumento de tipo é mais específico e nenhum argumento de tipo é menos específico do argumento de tipo correspondente no outro.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.
    • Um tipo de matriz é mais específico do que outro tipo de matriz (com o mesmo número de dimensões), se o tipo de elemento da primeira é mais específico do que o tipo de elemento da segunda.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.
  • Caso contrário, se um membro é um operador sem comparação de precisão e a outra é um operador elevado, a sem comparação de precisão é melhor.Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.
  • Caso contrário, nenhum membro da função é melhor.Otherwise, neither function member is better.

Melhor conversão de expressãoBetter conversion from expression

Dada uma conversão implícita C1 que converte de uma expressão E a um tipo T1e uma conversão implícita C2 que converte de uma expressão E a um tipo T2, C1 é um melhor conversão que C2 se E corresponder exatamente a T2 e mantém pelo menos um dos seguintes: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:

Expressão exatamente correspondenteExactly matching Expression

Considerando uma expressão E e um tipo T, E corresponda exatamente ao T se tiver mantido por um dos seguintes:Given an expression E and a type T, E exactly matches T if one of the following holds:

  • E tem um tipo S, e existe uma conversão de identidade de S para TE has a type S, and an identity conversion exists from S to T
  • E é uma função anônima, T é um tipo de delegado D ou um tipo de árvore de expressão Expression<D> e mantém por um dos seguintes: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:
    • Um tipo de retorno inferido X existe para o E no contexto da lista de parâmetros de D (tipo de retorno inferido), e existe uma conversão de identidade de X para o tipo de retorno 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
    • Qualquer um dos E é não assíncronas e D tem um tipo de retorno Y ou E é assíncrono e D tem um tipo de retorno Task<Y>, e uma das opções a seguir contém: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:
      • O corpo da E é uma expressão que exatamente correspondências YThe body of E is an expression that exactly matches Y
      • O corpo da E é um bloco de instrução onde cada instrução return retorna uma expressão que exatamente correspondências YThe body of E is a statement block where every return statement returns an expression that exactly matches Y

Melhor destino da conversãoBetter conversion target

Dois tipos diferentes de dado T1 e T2, T1 é um destino de conversão melhor que T2 se nenhuma conversão implícita de T2 para T1 existir, e pelo menos um dos seguintes contém: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:

  • Uma conversão implícita da T1 para T2 existeAn implicit conversion from T1 to T2 exists
  • T1 é um tipo de delegado D1 ou um tipo de árvore de expressão Expression<D1>, T2 é um tipo de delegado D2 ou um tipo de árvore de expressão Expression<D2>, D1 tem um tipo de retorno S1 e uma da contém a seguinte: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 void está retornandoD2 is void returning
    • D2 tem um tipo de retorno S2, e S1 é um destino de conversão melhor que S2D2 has a return type S2, and S1 is a better conversion target than S2
  • T1 está Task<S1>, T2 é Task<S2>, e S1 é um destino de conversão melhor que S2T1 is Task<S1>, T2 is Task<S2>, and S1 is a better conversion target than S2
  • T1 está S1 ou S1? onde S1 é um tipo integral com sinal, e T2 está S2 ou S2? onde S2 é um tipo integral sem sinal.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. Especificamente:Specifically:
    • S1 está sbyte e S2 é byte, ushort, uint, ou ulongS1 is sbyte and S2 is byte, ushort, uint, or ulong
    • S1 está short e S2 é ushort, uint, ou ulongS1 is short and S2 is ushort, uint, or ulong
    • S1 está int e S2 é uint, ou ulongS1 is int and S2 is uint, or ulong
    • S1 está long e S2 é ulongS1 is long and S2 is ulong

Sobrecarga em classes genéricasOverloading in generic classes

Embora assinaturas conforme declarado devem ser exclusivas, é possível que a substituição de argumentos de tipo resulta em assinaturas idênticas.While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. Nesses casos, as regras de resolução de sobrecarga acima de desempate escolherá o membro mais específico.In such cases, the tie-breaking rules of overload resolution above will pick the most specific member.

Os exemplos a seguir mostram as sobrecargas que são válidas e inválidas de acordo com essa regra: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);
}

Verificação de resolução de sobrecarga de dinâmica de tempo de compilaçãoCompile-time checking of dynamic overload resolution

Para operações de ligação mais dinamicamente o conjunto de possíveis candidatos para a resolução é desconhecido no tempo de compilação.For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. Em alguns casos, no entanto o conjunto de candidato é conhecido no tempo de compilação:In certain cases, however the candidate set is known at compile-time:

  • Chamadas de método estático com argumentos dinâmicosStatic method calls with dynamic arguments
  • Chamadas de método de instância em que o receptor não for uma expressão dinâmicaInstance method calls where the receiver is not a dynamic expression
  • Chamadas de indexador em que o receptor não for uma expressão dinâmicaIndexer calls where the receiver is not a dynamic expression
  • Chamadas de construtor com argumentos dinâmicosConstructor calls with dynamic arguments

Nesses casos, uma verificação limitada de tempo de compilação é executada para cada candidato ver se qualquer um deles, possivelmente, pode aplicar em tempo de execução. Essa verificação consiste as seguintes etapas: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:

  • Inferência de tipo parcial: Qualquer tipo de argumento que não depende diretamente ou indiretamente um argumento do tipo dynamic é inferido usando as regras da inferência de tipo.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. Os argumentos de tipo restantes são desconhecidos.The remaining type arguments are unknown.
  • Verificação de aplicabilidade parcial: Aplicabilidade é verificada de acordo com a membro da função aplicável, mas ignorando os parâmetros cujos tipos são desconhecidos.Partial applicability check: Applicability is checked according to Applicable function member, but ignoring parameters whose types are unknown.
  • Se nenhum candidato passar nesse teste, ocorrerá um erro de tempo de compilação.If no candidate passes this test, a compile-time error occurs.

Invocação de membro de funçãoFunction member invocation

Esta seção descreve o processo que ocorre em tempo de execução para invocar um membro de função específica.This section describes the process that takes place at run-time to invoke a particular function member. Supõe-se que um processo de tempo de associação já determinou que o membro específico para invocar, possivelmente, aplicando resolução de sobrecarga para um conjunto de membros da função de candidato.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.

Para fins de descrever o processo de invocação, os membros da função são divididos em duas categorias:For purposes of describing the invocation process, function members are divided into two categories:

  • Membros de função estática.Static function members. Esses são métodos estáticos, construtores de instância, os acessadores de propriedade estática e operadores definidos pelo usuário.These are instance constructors, static methods, static property accessors, and user-defined operators. Membros da função estáticos são sempre não virtual.Static function members are always non-virtual.
  • Membros da função de instância.Instance function members. Esses são métodos de instância, os acessadores de propriedade de instância e acessadores de indexador.These are instance methods, instance property accessors, and indexer accessors. Membros da função de instância são não virtual ou virtual e sempre são invocados em uma instância específica.Instance function members are either non-virtual or virtual, and are always invoked on a particular instance. A instância é calculada por uma expressão de instância, e se torna acessível dentro do membro da função como this (esse acesso).The instance is computed by an instance expression, and it becomes accessible within the function member as this (This access).

O processamento de tempo de execução de uma invocação de membro de função consiste em etapas a seguir, onde M é o membro da função e, se M é um membro de instância, E é a expressão da instância: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:

  • Se M é um membro da função estática:If M is a static function member:

  • Se M é um membro da função de instância declarado em um value_type:If M is an instance function member declared in a value_type:

    • E é avaliado.E is evaluated. Se essa avaliação causa uma exceção, nenhuma outra etapa é executada.If this evaluation causes an exception, then no further steps are executed.
    • Se E não é classificado como uma variável e, em seguida, uma variável local temporária do Edo tipo é criado e o valor de E é atribuído a essa variável.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 em seguida, ser reclassificado como uma referência para a variável local temporário.E is then reclassified as a reference to that temporary local variable. Variável temporária é acessível como this dentro de M, mas não em qualquer outra forma.The temporary variable is accessible as this within M, but not in any other way. Assim, somente quando E é uma variável true é possível para o chamador observar as alterações que M faz com this.Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.
    • A lista de argumentos é avaliada, conforme descrito em listas de argumentos.The argument list is evaluated as described in Argument lists.
    • M é invocado.M is invoked. A variável referenciada por E torna-se a variável referenciada por this.The variable referenced by E becomes the variable referenced by this.
  • Se M é um membro da função de instância declarado em um reference_type:If M is an instance function member declared in a reference_type:

    • E é avaliado.E is evaluated. Se essa avaliação causa uma exceção, nenhuma outra etapa é executada.If this evaluation causes an exception, then no further steps are executed.
    • A lista de argumentos é avaliada, conforme descrito em listas de argumentos.The argument list is evaluated as described in Argument lists.
    • Se o tipo de E é um value_type, uma conversão boxing (conversões Boxing) é executada para converter E para o tipo object, e E é considerado para ser do tipo object nas etapas a seguir.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. Nesse caso, M só pode ser um membro de System.Object.In this case, M could only be a member of System.Object.
    • O valor de E é verificado para ser válido.The value of E is checked to be valid. Se o valor de E está null, um System.NullReferenceException é lançada e nenhuma outra etapa é executada.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • A implementação de membro da função para invocar é determinada:The function member implementation to invoke is determined:
      • Se o tempo de associação de tipo de E é uma interface, o membro da função para invocar é a implementação de M fornecida pelo tipo de tempo de execução da instância referenciada por 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. Este membro da função é determinado pela aplicação das regras de mapeamento de interface (mapeamento de Interface) para determinar a implementação de M fornecida pelo tipo de tempo de execução da instância referenciada por 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.
      • Caso contrário, se M é um membro da função virtual, o membro da função para invocar é a implementação de M fornecida pelo tipo de tempo de execução da instância referenciada por 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. Este membro da função é determinado pela aplicação das regras para determinar a implementação mais derivada (métodos virtuais) de M em relação ao tipo de tempo de execução da instância referenciada por 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.
      • Caso contrário, M é um membro da função não virtual e é o membro da função para invocar M em si.Otherwise, M is a non-virtual function member, and the function member to invoke is M itself.
    • A implementação de membro da função determinada na etapa anterior é invocada.The function member implementation determined in the step above is invoked. O objeto referenciado por E torna-se o objeto referenciado por this.The object referenced by E becomes the object referenced by this.

Invocações de instâncias do boxInvocations on boxed instances

Um membro da função implementada em uma value_type pode ser invocado por meio de uma instância demarcada desse value_type nas seguintes situações:A function member implemented in a value_type can be invoked through a boxed instance of that value_type in the following situations:

  • Quando o membro da função é um override de um método herdado do tipo object e é invocado por meio de uma expressão de instância do tipo 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.
  • Quando o membro da função é uma implementação de um membro da função de interface e é invocado por meio de uma expressão de instância de um 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.
  • Quando o membro da função é invocado por meio de um delegado.When the function member is invoked through a delegate.

Nessas situações, a instância do box é considerada como tendo uma variável do value_type, e essa variável se torna a variável referenciada por this dentro a invocação de membro da função.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. Em particular, isso significa que, quando um membro da função é invocado em uma instância do box, é possível que o membro da função modificar o valor contido na instância do box.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.

Expressões primáriasPrimary expressions

Expressões primárias incluem as formas mais simples de expressões.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
    ;

Expressões primárias são divididas entre array_creation_expressions e primary_no_array_creation_expressions.Primary expressions are divided between array_creation_expressions and primary_no_array_creation_expressions. Tratar a expressão de criação de matriz dessa forma, em vez de listá-la junto com as outras formas de expressão simples, permite que a gramática para não permitir código potencialmente confuso, comoTreating 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];

Caso contrário, que poderiam ser interpretados comowhich would otherwise be interpreted as

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

LiteraisLiterals

Um primary_expression que consiste em um literal (literais) é classificado como um valor.A primary_expression that consists of a literal (Literals) is classified as a value.

Cadeias de caracteres interpoladasInterpolated strings

Uma interpolated_string_expression consiste em um $ sinal seguido por uma regular ou textual cadeia de caracteres literal, no qual os buracos, delimitadas por { e }, inclua expressões e formatação especificações.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. Uma expressão de cadeia de caracteres interpolada é o resultado de uma interpolated_string_literal que foi dividido em tokens individuais, conforme descrito em interpoladas literais de cadeia de caracteres.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)+
    ;

O constant_expression uma interpolação deve ter uma conversão implícita em int.The constant_expression in an interpolation must have an implicit conversion to int.

Uma interpolated_string_expression é classificado como um valor.An interpolated_string_expression is classified as a value. Se ele imediatamente é convertido em System.IFormattable ou System.FormattableString com uma conversão implícita de cadeia de caracteres interpolada (implícitas interpoladas conversões de cadeia de caracteres), a expressão de cadeia de caracteres interpolada tem esse tipo.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. Caso contrário, ele tem o tipo string.Otherwise, it has the type string.

Se for o tipo de uma cadeia de caracteres interpolada System.IFormattable ou System.FormattableString, o significado é uma chamada para 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. Se o tipo for string, o significado da expressão é uma chamada para string.Format.If the type is string, the meaning of the expression is a call to string.Format. Em ambos os casos, a lista de argumentos da chamada consiste em uma cadeia de caracteres de formato literal com espaços reservados para cada interpolação e um argumento para cada expressão correspondente para os espaços reservados.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.

A cadeia de caracteres de formato literal é construída da seguinte maneira, onde N é o número de interpolações em de interpolated_string_expression:The format string literal is constructed as follows, where N is the number of interpolations in the interpolated_string_expression:

  • Se um interpolated_regular_string_whole ou um interpolated_verbatim_string_whole segue o $ entrar, em seguida, o literal de cadeia de caracteres de formato é esse token.If an interpolated_regular_string_whole or an interpolated_verbatim_string_whole follows the $ sign, then the format string literal is that token.
  • Caso contrário, a cadeia de caracteres de formato literal consiste em:Otherwise, the format string literal consists of:
    • Primeiro o interpolated_regular_string_start ou interpolated_verbatim_string_startFirst the interpolated_regular_string_start or interpolated_verbatim_string_start
    • Em seguida, para cada número I partir 0 para N-1:Then for each number I from 0 to N-1:
      • A representação decimal de IThe decimal representation of I
      • Então, se correspondente interpolação tem um constant_expression, um , (vírgula) seguida pela representação decimal do valor da constant_expressionThen, if the corresponding interpolation has a constant_expression, a , (comma) followed by the decimal representation of the value of the constant_expression
      • Em seguida, a interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid ou interpolated_ verbatim_string_end imediatamente após a interpolação correspondente.Then the interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid or interpolated_verbatim_string_end immediately following the corresponding interpolation.

Os argumentos subsequentes são simplesmente o expressões da interpolações (se houver), na ordem.The subsequent arguments are simply the expressions from the interpolations (if any), in order.

TODO: exemplos.TODO: examples.

Nomes simplesSimple names

Um simple_name consiste em um identificador, opcionalmente seguido por uma lista de argumentos de tipo:A simple_name consists of an identifier, optionally followed by a type argument list:

simple_name
    : identifier type_argument_list?
    ;

Um simple_name é do formulário I ou do formulário I<A1,...,Ak>, onde I é um identificador único e <A1,...,Ak> é um recurso opcional type_argument_list.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. Quando nenhum type_argument_list é especificado, considere K seja zero.When no type_argument_list is specified, consider K to be zero. O simple_name é avaliado e classificados da seguinte maneira:The simple_name is evaluated and classified as follows:

  • Se K é zero e o simple_name aparece dentro de uma bloco e, se a blocodo (ou um delimitador blocodo) local espaço de declaração de variável (declarações) contém uma variável local, parâmetro ou constante com nome I, em seguida, o simple_name refere-se para a variável local, parâmetro ou constante e é classificado como uma variável ou um valor.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.

  • Se K é zero e o simple_name é exibida dentro do corpo de uma declaração de método genérico e se essa declaração inclui um parâmetro de tipo com nome I, em seguida, a simple_namese refere a esse parâmetro de tipo.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.

  • Caso contrário, para cada tipo de instância T (o tipo de instância), começando com o tipo de instância de declaração de tipo de delimitador imediatamente e continuando com o tipo de instância de cada classe delimitadora ou struct declaração (se houver):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):

    • Se K é zero e a declaração de T inclui um parâmetro de tipo com nome I, em seguida, o simple_name refere-se a esse parâmetro de tipo.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.
    • Caso contrário, se uma pesquisa de membro (pesquisa de membro) de I na T com K  argumentos de tipo produz uma correspondência:Otherwise, if a member lookup (Member lookup) of I in T with K type arguments produces a match:
      • Se T é o tipo de instância do tipo de classe ou struct imediatamente delimitador e a pesquisa identifica um ou mais métodos, o resultado é um grupo de método com uma expressão de instância associada do 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. Se uma lista de argumentos de tipo foi especificada, ele será usado na chamada de um método genérico (invocações de método).If a type argument list was specified, it is used in calling a generic method (Method invocations).
      • Caso contrário, se T é o tipo de instância do tipo imediatamente delimitador de classe ou struct, se a pesquisa identifica um membro de instância, e se a referência ocorre dentro do corpo de um construtor de instância, um método de instância ou um acessador de instância, o resultado é o mesmo que um acesso de membro (acesso de membro) do formulário 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. Isso só pode acontecer quando K é zero.This can only happen when K is zero.
      • Caso contrário, o resultado é o mesmo que um acesso de membro (acesso de membro) do formulário 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>. Nesse caso, ele é um erro de tempo de associação para o simple_name para se referir a um membro de instância.In this case, it is a binding-time error for the simple_name to refer to an instance member.
  • Caso contrário, para cada namespace N, começando com o namespace no qual o simple_name ocorre, continuando com cada delimitador namespace (se houver) e terminando com o namespace global, são as seguintes etapas avaliada até que uma entidade está localizada: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:

    • Se K é zero e I é o nome de um namespace em N, então:If K is zero and I is the name of a namespace in N, then:
      • Se o local onde o simple_name ocorre estiver envolvido por uma declaração de namespace N e a declaração de namespace contém uma extern_alias_directive ou using_alias_directive que associa o nome I com um namespace ou tipo, em seguida, a simple_name é ambíguo e ocorrer um erro de tempo de compilação.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.
      • Caso contrário, o simple_name refere-se ao namespace chamado I em N.Otherwise, the simple_name refers to the namespace named I in N.
    • Caso contrário, se N contém um tipo acessível com o nome I e K  , em seguida, os parâmetros de tipo:Otherwise, if N contains an accessible type having name I and K type parameters, then:
      • Se K é zero e o local onde o simple_name ocorre é incluído por uma declaração de namespace N e a declaração de namespace contém um extern_alias_directiveou using_alias_directive que associa o nome I com um namespace ou tipo, em seguida, a simple_name é ambíguo e ocorrer um erro de tempo de compilação.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.
      • Caso contrário, o namespace_or_type_name refere-se para o tipo construído com os argumentos de tipo em questão.Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
    • Caso contrário, se o local em que o simple_name ocorre é incluído por uma declaração de namespace para N:Otherwise, if the location where the simple_name occurs is enclosed by a namespace declaration for N:
      • Se K é zero e a declaração de namespace contém uma extern_alias_directive ou using_alias_directive que associa o nome I com um namespace importado ou tipo, em seguida, a simple_name refere-se a esse namespace ou tipo.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.
      • Caso contrário, se as declarações de namespaces e o tipo importado pela using_namespace_directives e using_static_directives da declaração do namespace conter exatamente um tipo acessível ou tendo o nome de membro estático sem extensão I e K  parâmetros de tipo, o simple_name refere-se a esse tipo ou membro construído com os argumentos de tipo em questão.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.
      • Caso contrário, se os tipos e namespaces importados pelo using_namespace_directives da declaração do namespace contêm mais de um tipo acessível ou ter um nome de membro estático do método de extensão não I e K  parâmetros de tipo, o simple_name é ambíguo e ocorre um erro.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.

    Observe que toda essa etapa é exatamente paralela para a etapa correspondente no processamento de uma namespace_or_type_name (nomes de Namespace e tipo).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).

  • Caso contrário, o simple_name é indefinido e ocorrer um erro de tempo de compilação.Otherwise, the simple_name is undefined and a compile-time error occurs.

Expressões entre parêntesesParenthesized expressions

Um parenthesized_expression consiste em um expressão entre parênteses.A parenthesized_expression consists of an expression enclosed in parentheses.

parenthesized_expression
    : '(' expression ')'
    ;

Um parenthesized_expression é avaliada por avaliar o expressão dentro dos parênteses.A parenthesized_expression is evaluated by evaluating the expression within the parentheses. Se o expressão dentro dos parênteses denota um namespace ou tipo, ocorre um erro de tempo de compilação.If the expression within the parentheses denotes a namespace or type, a compile-time error occurs. Caso contrário, o resultado do parenthesized_expression é o resultado da avaliação de independente expressão.Otherwise, the result of the parenthesized_expression is the result of the evaluation of the contained expression.

Acesso de membrosMember access

Um member_access consiste em um primary_expression, um predefined_type, ou um qualified_alias_member, seguido por um"."token, seguido por um identificador, opcionalmente seguido por um 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'
    ;

O qualified_alias_member produção é definida no qualificadores alias de Namespace.The qualified_alias_member production is defined in Namespace alias qualifiers.

Um member_access é do formulário E.I ou do formulário E.I<A1, ..., Ak>, onde E é uma expressão primária I é um identificador único e <A1, ..., Ak> é um recurso opcional type_argument_list.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. Quando nenhum type_argument_list é especificado, considere K seja zero.When no type_argument_list is specified, consider K to be zero.

Um member_access com um primary_expression do tipo dynamic associado dinamicamente (vinculação dinâmica).A member_access with a primary_expression of type dynamic is dynamically bound (Dynamic binding). Nesse caso, o compilador classifica o acesso de membro como um acesso de propriedade do tipo dynamic.In this case the compiler classifies the member access as a property access of type dynamic. As regras abaixo para determinar o significado do member_access , em seguida, são aplicadas em tempo de execução, usando o tipo de tempo de execução em vez do tipo de tempo de compilação da 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. Se essa classificação de tempo de execução leva a um grupo de métodos, o acesso de membro deve ser o primary_expression de uma 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.

O member_access é avaliado e classificados da seguinte maneira:The member_access is evaluated and classified as follows:

  • Se K é zero e E é um namespace e E contém um namespace aninhado com nome I, o resultado será desse namespace.If K is zero and E is a namespace and E contains a nested namespace with name I, then the result is that namespace.
  • Caso contrário, se E é um namespace e E contém um tipo acessível com nome I e K  parâmetros de tipo, em seguida, o resultado será aquele tipo construído com os argumentos de tipo em questão.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.
  • Se E é um predefined_type ou uma primary_expression classificado como um tipo, se E não é um parâmetro de tipo e se uma pesquisa de membro (depesquisademembro) dos I na E com K  parâmetros de tipo produz uma correspondência, em seguida, E.I é avaliado e classificados da seguinte maneira: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:
    • Se I identifica um tipo, em seguida, o resultado será aquele tipo construído com os argumentos de tipo em questão.If I identifies a type, then the result is that type constructed with the given type arguments.
    • Se I identifica um ou mais métodos, o resultado será um grupo de métodos sem expressão de instância associada.If I identifies one or more methods, then the result is a method group with no associated instance expression. Se uma lista de argumentos de tipo foi especificada, ele será usado na chamada de um método genérico (invocações de método).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Se I identifica um static propriedade e, em seguida, o resultado é um acesso de propriedade sem expressão de instância associada.If I identifies a static property, then the result is a property access with no associated instance expression.
    • Se I identifica um static campo:If I identifies a static field:
      • Se o campo estiver readonly e a referência ocorre fora do construtor estático da classe ou struct em que o campo é declarado e, em seguida, o resultado é um valor, ou seja, o valor do campo estático I em E.If the field is readonly and the reference occurs outside the static constructor of the class or struct in which the field is declared, then the result is a value, namely the value of the static field I in E.
      • Caso contrário, o resultado é uma variável, ou seja, o campo estático I em E.Otherwise, the result is a variable, namely the static field I in E.
    • Se I identifica um static eventos:If I identifies a static event:
      • Se a referência ocorre dentro da classe ou struct em que o evento é declarado e o evento foi declarado sem event_accessor_declarations (eventos), em seguida, E.I é processado exatamente como se I foram um campo estático.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.
      • Caso contrário, o resultado é um acesso de evento sem expressão de instância associada.Otherwise, the result is an event access with no associated instance expression.
    • Se I identifica uma constante, o resultado será um valor, ou seja, o valor dessa constante.If I identifies a constant, then the result is a value, namely the value of that constant.
    • Se I identifica um membro de enumeração, o resultado será um valor, ou seja, o valor desse membro de enumeração.If I identifies an enumeration member, then the result is a value, namely the value of that enumeration member.
    • Caso contrário, E.I é uma referência de membro inválido e ocorre um erro de tempo de compilação.Otherwise, E.I is an invalid member reference, and a compile-time error occurs.
  • Se E é um acesso de propriedade, acesso de indexador, variável ou valor, o tipo do qual é Te uma pesquisa de membro (pesquisa de membro) do I na T com K  argumentos de tipo produz uma correspondência, em seguida, E.I é avaliado e classificados da seguinte maneira: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:
    • Primeiro, se E é uma propriedade ou acesso do indexador, então o valor da propriedade ou indexador acesso é obtido (valores de expressões) e E é reclassificado como um valor.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.
    • Se I identifica um ou mais métodos, o resultado será um grupo de métodos com uma expressão de instância associada do E.If I identifies one or more methods, then the result is a method group with an associated instance expression of E. Se uma lista de argumentos de tipo foi especificada, ele será usado na chamada de um método genérico (invocações de método).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Se I identifica uma propriedade de instânciaIf I identifies an instance property,
      • Se E está this, I identifica uma propriedade implementada automaticamente (implementada automaticamente propriedades) sem um setter e a referência ocorre dentro de um construtor de instância para um tipo de classe ou struct T, em seguida, o resultado é uma variável, ou seja, o campo de suporte oculto para a propriedade automática fornecida pelo I na instância do T fornecido pela 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.
      • Caso contrário, o resultado é um acesso de propriedade com uma expressão de instância associada do E.Otherwise, the result is a property access with an associated instance expression of E.
    • Se T é um class_type e I identifica um campo de instância disso class_type:If T is a class_type and I identifies an instance field of that class_type:
      • Se o valor de E está null, em seguida, um System.NullReferenceException é gerada.If the value of E is null, then a System.NullReferenceException is thrown.
      • Caso contrário, se o campo estiver readonly e a referência ocorre fora de um construtor de instância da classe na qual o campo é declarado e, em seguida, o resultado é um valor, ou seja, o valor do campo I no objeto referenciado pelo E.Otherwise, if the field is readonly and the reference occurs outside an instance constructor of the class in which the field is declared, then the result is a value, namely the value of the field I in the object referenced by E.
      • Caso contrário, o resultado é uma variável, ou seja, o campo I no objeto referenciado pelo E.Otherwise, the result is a variable, namely the field I in the object referenced by E.
    • Se T é um struct_type e I identifica um campo de instância disso struct_type:If T is a struct_type and I identifies an instance field of that struct_type:
      • Se E é um valor, ou se o campo estiver readonly e a referência ocorre fora de um construtor de instância do struct em que o campo é declarado e, em seguida, o resultado é um valor, ou seja, o valor do campo I na instância do struct fornecida por  E.If E is a value, or if the field is readonly and the reference occurs outside an instance constructor of the struct in which the field is declared, then the result is a value, namely the value of the field I in the struct instance given by E.
      • Caso contrário, o resultado é uma variável, ou seja, o campo I na instância do struct fornecida pelo E.Otherwise, the result is a variable, namely the field I in the struct instance given by E.
    • Se I identifica um evento da instância:If I identifies an instance event:
      • Se a referência ocorre dentro da classe ou struct em que o evento é declarado e o evento foi declarado sem event_accessor_declarations (eventos), e a referência não ocorre como o lado esquerdo de uma += ou -= operador, em seguida, E.I é processado exatamente como se I foi um campo de instância.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.
      • Caso contrário, o resultado é um evento de acesso com uma expressão de instância associada do E.Otherwise, the result is an event access with an associated instance expression of E.
  • Caso contrário, é feita uma tentativa para processar E.I como uma invocação de método de extensão (invocações de método de extensão).Otherwise, an attempt is made to process E.I as an extension method invocation (Extension method invocations). Se isso falhar, E.I é uma referência de membro inválido e ocorre um erro em tempo de vinculação.If this fails, E.I is an invalid member reference, and a binding-time error occurs.

Nomes idênticos de simples e nomes de tipoIdentical simple names and type names

Em um acesso de membro do formulário E.I, se E é um identificador único e se o significado dos E como um simple_name (nomes simples) é uma constante, campo, propriedade, variável local ou parâmetro com o mesmo tipo que o significado dos E como um type_name (nomes de Namespace e tipo), em seguida, os dois significados possíveis de E são permitido.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. Os dois significados possíveis das E.I nunca são ambíguas, desde I necessariamente deve ser um membro do tipo E em ambos os casos.The two possible meanings of E.I are never ambiguous, since I must necessarily be a member of the type E in both cases. Em outras palavras, a regra simplesmente permite acesso a membros estáticos e tipos aninhados de E onde caso contrário, seria ter ocorrido um erro de tempo de compilação.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. Por exemplo: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
    }
}

Ambiguidades de gramáticaGrammar ambiguities

As produções para simple_name (nomes simples) e member_access (acesso de membro) pode dar origem a ambiguidades no gramática de expressões.The productions for simple_name (Simple names) and member_access (Member access) can give rise to ambiguities in the grammar for expressions. Por exemplo, a instrução:For example, the statement:

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

pode ser interpretado como uma chamada para F com dois argumentos, G < A e B > (7).could be interpreted as a call to F with two arguments, G < A and B > (7). Como alternativa, ele poderia ser interpretado como uma chamada para F com um argumento, que é uma chamada para um método genérico G com dois argumentos de tipo e um argumento regular.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.

Se uma sequência de tokens pode ser analisada (no contexto) como um simple_name (nomes simples), member_access (acesso de membro), ou pointer_member_access (acesso de membro do ponteiro) terminando com um type_argument_list (argumentos de tipo), o imediatamente após o fechamento do token > token é examinado.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. Se ele for um dosIf it is one of

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

em seguida, a type_argument_list é mantido como parte do simple_name, member_access ou pointer_member_access e qualquer a análise da sequência de tokens de outra possíveis será descartada.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. Caso contrário, o type_argument_list não é considerado parte do simple_name, member_access ou pointer_member_access, mesmo se não houver nenhuma análise da sequência de tokens de outro possíveis.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. Observe que essas regras não são aplicadas durante a análise de um type_argument_list em um namespace_or_type_name (nomes de Namespace e tipo).Note that these rules are not applied when parsing a type_argument_list in a namespace_or_type_name (Namespace and type names). A instruçãoThe statement

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

será, de acordo com a esta regra, interpretada como uma chamada para F com um argumento, que é uma chamada para um método genérico G com dois argumentos de tipo e um argumento regular.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. As instruçõesThe statements

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

cada uma ser interpretada como uma chamada para F com dois argumentos.will each be interpreted as a call to F with two arguments. A instruçãoThe statement

x = F < A > +y;

será interpretado como um operador menor que, maior que o operador e operador de adição unário, como se tivesse sido escrita a instrução x = (F < A) > (+y), em vez de como uma simple_name com um type_argument_list seguido por um operador de adição binária.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. Na instruçãoIn the statement

x = y is C<T> + z;

os tokens C<T> são interpretados como uma namespace_or_type_name com um type_argument_list.the tokens C<T> are interpreted as a namespace_or_type_name with a type_argument_list.

Expressões de invocaçãoInvocation expressions

Uma invocation_expression é usado para invocar um método.An invocation_expression is used to invoke a method.

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

Uma invocation_expression associado dinamicamente (vinculação dinâmica) se tiver mantido pelo menos um dos seguintes:An invocation_expression is dynamically bound (Dynamic binding) if at least one of the following holds:

  • O primary_expression tem o tipo de tempo de compilação dynamic.The primary_expression has compile-time type dynamic.
  • Pelo menos um argumento de opcional argument_list tem o tipo de tempo de compilação dynamic e o primary_expression não tem um tipo de delegado.At least one argument of the optional argument_list has compile-time type dynamic and the primary_expression does not have a delegate type.

Nesse caso, o compilador classifica os invocation_expression como um valor do tipo dynamic.In this case the compiler classifies the invocation_expression as a value of type dynamic. As regras abaixo para determinar o significado do invocation_expression , em seguida, são aplicadas em tempo de execução, usando o tipo de tempo de execução em vez do tipo de tempo de compilação do primary_expression e argumentos que têm o tipo de tempo de compilação dynamic.The rules below to determine the meaning of the invocation_expression are then applied at run-time, using the run-time type instead of the compile-time type of those of the primary_expression and arguments which have the compile-time type dynamic. Se o primary_expression não tem o tipo de tempo de compilação dynamic, em seguida, a invocação do método passa por uma verificação de tempo de compilação limitada, conforme descrito em verificação de resolução de sobrecarga de dinâmica de tempo de compilação .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.

O primary_expression de uma invocation_expression deve ser um grupo de método ou um valor de um delegate_type.The primary_expression of an invocation_expression must be a method group or a value of a delegate_type. Se o primary_expression é um grupo de método, o invocation_expression é uma invocação de método (invocações de método).If the primary_expression is a method group, the invocation_expression is a method invocation (Method invocations). Se o primary_expression é um valor de uma delegate_type, o invocation_expression é uma invocação de delegado (delegar invocações).If the primary_expression is a value of a delegate_type, the invocation_expression is a delegate invocation (Delegate invocations). Se o primary_expression não é um grupo de métodos nem um valor de uma delegate_type, ocorrerá um erro em tempo de associação.If the primary_expression is neither a method group nor a value of a delegate_type, a binding-time error occurs.

Opcional argument_list (listas de argumentos) fornece os valores ou referências de variáveis para os parâmetros do método.The optional argument_list (Argument lists) provides values or variable references for the parameters of the method.

O resultado da avaliação de uma invocation_expression são classificados da seguinte maneira:The result of evaluating an invocation_expression is classified as follows:

  • Se o invocation_expression invoca um método ou um delegado que retorna void, o resultado é que nada.If the invocation_expression invokes a method or delegate that returns void, the result is nothing. Uma expressão que é classificada como nada é permitido apenas no contexto de um statement_expression (instruções de expressão) ou como o corpo de um lambda_expression(Expressões de função anônima).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). Caso contrário, ocorrerá um erro em tempo de vinculação.Otherwise a binding-time error occurs.
  • Caso contrário, o resultado é um valor do tipo retornado pelo método ou delegate.Otherwise, the result is a value of the type returned by the method or delegate.

Invocações de métodoMethod invocations

Para uma invocação de método, o primary_expression da invocation_expression deve ser um grupo de método.For a method invocation, the primary_expression of the invocation_expression must be a method group. O grupo de método identifica um método para invocar ou o conjunto de métodos sobrecarregados para escolher um método específico para invocar.The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke. No último caso, a determinação do método específico para invocar se baseia o contexto fornecido pelos tipos dos argumentos de 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.

O processamento de tempo de associação de uma invocação de método do formulário M(A), onde M é um grupo de métodos (incluindo, possivelmente, um type_argument_list), e A é um recurso opcional argument_ lista, consiste as seguintes etapas: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:

  • O conjunto de métodos de candidato para a invocação do método é construído.The set of candidate methods for the method invocation is constructed. Para cada método de F associada ao grupo de método M:For each method F associated with the method group M:
    • Se F é não genérica, F é um candidato quando:If F is non-generic, F is a candidate when:
    • Se F é genérico e M não tem nenhuma lista de argumentos de tipo F é um candidato quando:If F is generic and M has no type argument list, F is a candidate when:
      • Inferência de tipo (inferência de tipo) for bem-sucedida, inferir uma lista de argumentos de tipo para a chamada, eType inference (Type inference) succeeds, inferring a list of type arguments for the call, and
      • Depois que os argumentos de tipo inferidos são substituídos por parâmetros de tipo correspondente do método, todos os tipos construídos na lista de parâmetros de F atender às suas restrições (atendendo às restrições de) e a lista de parâmetro de F é aplicável em relação às A (membro da função aplicável).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).
    • Se F é genérico e M inclui uma lista de argumentos de tipo F é um candidato quando:If F is generic and M includes a type argument list, F is a candidate when:
      • F tem o mesmo número de parâmetros de tipo de método como foram fornecidos na lista de argumentos de tipo, eF has the same number of method type parameters as were supplied in the type argument list, and
      • Depois que os argumentos de tipo são substituídos por parâmetros de tipo correspondente do método, todos os tipos construídos na lista de parâmetros de F atender às suas restrições (atendendo às restrições) e a lista de parâmetros de F é aplicável em relação às A (membro da função aplicável).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).
  • O conjunto de métodos de candidato é reduzido para conter apenas métodos de tipos mais derivados: Para cada método de C.F no conjunto, onde C é o tipo no qual o método F for declarado, todos os métodos declarados em um tipo base de C são removidas do conjunto de.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. Além disso, se C é um tipo de classe diferente de object, todos os métodos declarados em um tipo de interface são removidos do conjunto.Furthermore, if C is a class type other than object, all methods declared in an interface type are removed from the set. (Essa última regra só tem efeito quando o grupo de método foi o resultado de uma pesquisa de membro em um parâmetro de tipo que tem uma classe base efetivada que não seja o objeto e uma interface de efetivada vazio definido.)(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.)
  • Se o conjunto de métodos de candidato resultante está vazio, processamento adicional ao longo das etapas a seguir são abandonados e, em vez disso, é feita uma tentativa para processar a invocação de uma invocação de método de extensão (invocações de método de extensão).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). Se isso falhar, então nenhum método aplicável existe e ocorre um erro em tempo de vinculação.If this fails, then no applicable methods exist, and a binding-time error occurs.
  • O melhor método do conjunto de métodos de candidato é identificado usando as regras de resolução de sobrecarga de resolução de sobrecarga.The best method of the set of candidate methods is identified using the overload resolution rules of Overload resolution. Se um único método melhor não pode ser identificado, a invocação do método é ambígua e ocorre um erro em tempo de vinculação.If a single best method cannot be identified, the method invocation is ambiguous, and a binding-time error occurs. Ao executar a resolução de sobrecarga, os parâmetros de um método genérico são considerados depois de substituir os argumentos de tipo (fornecida ou inferido) para os parâmetros de tipo correspondente do método.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.
  • Validação final do método melhor escolhido é executada:Final validation of the chosen best method is performed:
    • O método é validado no contexto do grupo de método: Se o melhor método é um método estático, o grupo de método deve ter resultado de uma simple_name ou um member_access por meio de um tipo.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. Se o melhor método é um método de instância, o grupo de método deve ter resultado de uma simple_name, um member_access por meio de uma variável ou um valor, ou uma 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. Se nenhum desses requisitos for true, ocorrerá um erro de tempo de associação.If neither of these requirements is true, a binding-time error occurs.
    • Se o melhor método é um método genérico, os argumentos de tipo (fornecida ou inferido) são verificados em relação às restrições (atendendo às restrições de) declarado no método genérico.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. Se qualquer argumento de tipo não satisfaz a ões correspondente no parâmetro de tipo, ocorrerá um erro de tempo de associação.If any type argument does not satisfy the corresponding constraint(s) on the type parameter, a binding-time error occurs.

Depois que um método foi selecionado e validado no tempo de associação, as etapas acima, a invocação de tempo de execução real é processada de acordo com as regras da invocação de membro de função descrito na verificação de resolução de sobrecarga de dinâmica de tempo de compilação .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.

O efeito intuitivo das regras de resolução descrito acima é da seguinte maneira: Para localizar o método específico, invocado por uma invocação de método, comece com o tipo indicado pela invocação do método e continuar a cadeia de herança até que a declaração de pelo menos um método aplicável, acessível e não de substituição for encontrada.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. Em seguida, realizar a inferência de tipo e resolução no conjunto de métodos aplicáveis, acessíveis e não-override declaradas nesse tipo de sobrecarga e invocar o método selecionado, portanto.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. Se nenhum método foi encontrado, tente em vez disso processar a invocação de uma invocação de método de extensão.If no method was found, try instead to process the invocation as an extension method invocation.

Invocações de método de extensãoExtension method invocations

Em uma invocação de método (invocações em instâncias demarcadas) de uma das formasIn a method invocation (Invocations on boxed instances) of one of the forms

expr . identifier ( )

expr . identifier ( args )

expr . identifier < typeargs > ( )

expr . identifier < typeargs > ( args )

Se o processamento normal de invocação não encontrar nenhum método aplicável, é feita uma tentativa para processar a construção de uma invocação de método de extensão.if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. Se expr ou qualquer um dos args tem o tipo de tempo de compilação dynamic, métodos de extensão não serão aplicada.If expr or any of the args has compile-time type dynamic, extension methods will not apply.

O objetivo é encontrar a melhor type_name C, de modo que a invocação de método estático correspondentes podem ocorrer: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 )

Um método de extensão Ci.Mj está qualificados se:An extension method Ci.Mj is eligible if:

  • Ci é uma classe não genérica, não aninhadasCi is a non-generic, non-nested class
  • O nome da Mj é identificadorThe name of Mj is identifier
  • Mj é aplicável quando aplicado aos argumentos como um método estático, como mostrado acima e acessívelMj is accessible and applicable when applied to the arguments as a static method as shown above
  • Existe uma identidade implícitas, referência ou conversão boxing a partir expr para o tipo do primeiro parâmetro de Mj.An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter of Mj.

A pesquisa de C procede da seguinte maneira:The search for C proceeds as follows:

  • Começando com a mais próxima declaração namespace delimitador, continuando com cada declaração de namespace delimitador e terminando com a unidade de compilação que contém, tentativas sucessivas são feitas para localizar um conjunto de candidatos de métodos de extensão: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:
    • Se a unidade de compilação ou de namespace determinada diretamente contém declarações de tipo não genérico Ci com métodos de extensão qualificados Mj, em seguida, o conjunto desses métodos de extensão é o conjunto de candidatos.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.
    • Se tipos Ci importados pelo using_static_declarations e diretamente declarados em namespaces importados pelo using_namespace_directives na unidade de especificada namespace ou de compilação diretamente contém métodos de extensão qualificados Mj, em seguida, o conjunto desses métodos de extensão é o conjunto de candidatos.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.
  • Se nenhum conjunto de candidato for encontrado em qualquer unidade de compilação ou de declaração de namespace delimitador, ocorrerá um erro de tempo de compilação.If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
  • Caso contrário, a resolução de sobrecarga é aplicada ao candidato definido conforme descrito em (resolução de sobrecarga).Otherwise, overload resolution is applied to the candidate set as described in (Overload resolution). Se nenhum método único de melhor for encontrado, ocorrerá um erro de tempo de compilação.If no single best method is found, a compile-time error occurs.
  • C é o tipo no qual o melhor método é declarado como um método de extensão.C is the type within which the best method is declared as an extension method.

Usando o C como um destino, a chamada de método é processada como uma invocação de método estático (verificação de resolução de sobrecarga de dinâmica de tempo de compilação).Using C as a target, the method call is then processed as a static method invocation (Compile-time checking of dynamic overload resolution).

As regras acima significam que os métodos de instância têm precedência sobre métodos de extensão, que os métodos de extensão disponíveis em declarações de namespace interno têm precedência sobre métodos de extensão disponíveis em declarações de namespace externo e essa extensão métodos declarados diretamente em um namespace têm precedência sobre métodos de extensão, importados para o mesmo namespace com o uso de uma diretiva de namespace.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. Por exemplo: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)
    }
}

No exemplo, Bdo método tem precedência sobre o primeiro método de extensão, e Cdo método tem precedência sobre os dois métodos de extensão.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();
        }
    }
}

A saída deste exemplo é:The output of this example is:

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

D.G tem precedência sobre C.G, e E.F prevalece sobre ambos D.F e C.F.D.G takes precedence over C.G, and E.F takes precedence over both D.F and C.F.

Invocações delegadasDelegate invocations

Para uma invocação de delegado, o primary_expression da invocation_expression deve ser um valor de um delegate_type.For a delegate invocation, the primary_expression of the invocation_expression must be a value of a delegate_type. Além disso, considerando o delegate_type ser um membro da função com a mesma lista de parâmetros como o delegate_type, o delegate_type deve ser aplicável ( Membro da função aplicáveis) com relação ao argument_list dos 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.

O processamento de tempo de execução de uma invocação de delegado do formulário D(A), onde D é um primary_expression de um delegate_type e A é um opcionalargument_list, consiste as seguintes etapas: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 é avaliado.D is evaluated. Se essa avaliação causa uma exceção, nenhuma outra etapa é executada.If this evaluation causes an exception, no further steps are executed.
  • O valor de D é verificado para ser válido.The value of D is checked to be valid. Se o valor de D está null, um System.NullReferenceException é lançada e nenhuma outra etapa é executada.If the value of D is null, a System.NullReferenceException is thrown and no further steps are executed.
  • Caso contrário, D é uma referência a uma instância de delegado.Otherwise, D is a reference to a delegate instance. Invocações de membro de função (verificação de resolução de sobrecarga de dinâmica de tempo de compilação) são executadas em cada uma das entidades que pode ser chamadas na lista de invocação do delegado.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. Para entidades que pode ser chamadas consiste em uma instância e o método de instância, a instância para a invocação é a instância contida na entidade que pode ser chamada.For callable entities consisting of an instance and instance method, the instance for the invocation is the instance contained in the callable entity.

Acesso de elementoElement access

Uma element_access consiste em um primary_no_array_creation_expression, seguido por um "[" token, seguido por um argument_list, seguido por um " ]"token.An element_access consists of a primary_no_array_creation_expression, followed by a "[" token, followed by an argument_list, followed by a "]" token. O argument_list consiste em um ou mais argumentos, separados por vírgulas.The argument_list consists of one or more arguments, separated by commas.

element_access
    : primary_no_array_creation_expression '[' expression_list ']'
    ;

O argument_list de uma element_access não pode conter ref ou out argumentos.The argument_list of an element_access is not allowed to contain ref or out arguments.

Uma element_access associado dinamicamente (vinculação dinâmica) se tiver mantido pelo menos um dos seguintes:An element_access is dynamically bound (Dynamic binding) if at least one of the following holds:

  • O primary_no_array_creation_expression tem o tipo de tempo de compilação dynamic.The primary_no_array_creation_expression has compile-time type dynamic.
  • Pelo menos uma expressão do argument_list tem o tipo de tempo de compilação dynamic e o primary_no_array_creation_expression não tem um tipo de matriz.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.

Nesse caso, o compilador classifica os element_access como um valor do tipo dynamic.In this case the compiler classifies the element_access as a value of type dynamic. As regras abaixo para determinar o significado do element_access , em seguida, são aplicadas em tempo de execução, usando o tipo de tempo de execução em vez do tipo de tempo de compilação do primary_no_array_creation_expressione argument_list expressões que têm o tipo de tempo de compilação 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. Se o primary_no_array_creation_expression não tem o tipo de tempo de compilação dynamic, em seguida, o acesso de elemento passa por uma verificação de tempo de compilação limitada, conforme descrito em verificando dinâmico de tempo de compilação resolução de sobrecarga.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.

Se o primary_no_array_creation_expression de uma element_access é um valor de um array_type, o element_access é um acesso de matriz (acesso de matriz).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). Caso contrário, o primary_no_array_creation_expression deve ser uma variável ou um valor de uma classe, struct ou tipo de interface que tem um ou mais membros de indexador, nesse caso, o element_access é um acesso do indexador (acesso do indexador).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).

Acesso de matrizArray access

Para obter um acesso de matriz, o primary_no_array_creation_expression da element_access deve ser um valor de um array_type.For an array access, the primary_no_array_creation_expression of the element_access must be a value of an array_type. Além disso, o argument_list de uma matriz acesso não é permitido para conter argumentos nomeados. O número de expressões na argument_list deve ser o mesmo que a classificação do array_type, e cada expressão deve ser do tipo int, uint, long, ulong, ou deve ser implicitamente conversível para um ou mais desses tipos.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.

O resultado da avaliação de um acesso à matriz é uma variável do tipo de elemento da matriz, ou seja, o elemento de matriz selecionado pelos valores das expressões na 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.

O processamento de tempo de execução de um acesso de matriz no formato P[A], onde P é um primary_no_array_creation_expression de um array_type e A é um argument_list, consiste as seguintes etapas: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 é avaliado.P is evaluated. Se essa avaliação causa uma exceção, nenhuma outra etapa é executada.If this evaluation causes an exception, no further steps are executed.
  • As expressões de índice do argument_list são avaliados na ordem da esquerda para a direita.The index expressions of the argument_list are evaluated in order, from left to right. Após a avaliação de cada expressão de índice, uma conversão implícita (conversões implícitas) é executada para um dos seguintes tipos: 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. O primeiro tipo nessa lista para o qual existe uma conversão implícita é escolhido.The first type in this list for which an implicit conversion exists is chosen. Por exemplo, se a expressão de índice é do tipo short , em seguida, uma conversão implícita para int é executada, desde a conversões implícitas de short para int bidirecionalmente short para long são possíveis.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. Se a avaliação de uma expressão de índice ou a conversão implícita subsequente faz com que uma exceção, nenhuma expressão de índice adicional é avaliado, e nenhuma outra etapas são executadas.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.
  • O valor de P é verificado para ser válido.The value of P is checked to be valid. Se o valor de P está null, um System.NullReferenceException é lançada e nenhuma outra etapa é executada.If the value of P is null, a System.NullReferenceException is thrown and no further steps are executed.
  • O valor de cada expressão na argument_list é verificado em relação os limites reais de cada dimensão da instância de matriz referenciada por 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. Se um ou mais valores estão fora do intervalo, um System.IndexOutOfRangeException é lançada e nenhuma outra etapa é executada.If one or more values are out of range, a System.IndexOutOfRangeException is thrown and no further steps are executed.
  • O local do elemento da matriz fornecido pelas expressões de índice é computado, e esse local se tornará o resultado do acesso de matriz.The location of the array element given by the index expression(s) is computed, and this location becomes the result of the array access.

Acesso de indexadorIndexer access

Para acessar um indexador, o primary_no_array_creation_expression da element_access deve ser uma variável ou um valor de uma classe, struct ou tipo de interface, e esse tipo deve implementar uma ou mais indexadores são aplicáveis em relação à argument_list da 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.

O processamento de tempo de associação de um acesso do indexador do formulário P[A], onde P é um primary_no_array_creation_expression de uma classe, struct ou tipo de interface T, e A é um argument_list, consiste as seguintes etapas:The binding-time processing of an indexer access of the form P[A], where P is a primary_no_array_creation_expression of a class, struct, or interface type T, and A is an argument_list, consists of the following steps:

  • O conjunto de indexadores fornecidos pelo T é construído.The set of indexers provided by T is constructed. O conjunto consiste em todos os indexadores declarados na T ou um tipo base T que não estão override declarações e pode ser acessada no contexto atual (acesso de membro).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).
  • O conjunto é reduzido para esses indexadores são aplicáveis e não ocultos por outros indexadores.The set is reduced to those indexers that are applicable and not hidden by other indexers. As seguintes regras são aplicadas a cada indexador S.I no conjunto, onde S é o tipo no qual o indexador I é declarado: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:
    • Se I não é aplicável em relação às A (membro da função aplicável), em seguida, I é removido do conjunto.If I is not applicable with respect to A (Applicable function member), then I is removed from the set.
    • Se I é aplicável em relação às A (membro da função aplicável), em seguida, todos os indexadores declarados em um tipo base de S são removidas do conjunto de.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.
    • Se I é aplicável em relação às A (membro da função aplicável) e S é um tipo de classe diferente de object, declarados em uma interface de todos os indexadores são removidos do conjunto.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.
  • Se o conjunto resultante de indexadores de candidato estiver vazio, em seguida, sem indexadores aplicáveis existirem e ocorre um erro em tempo de vinculação.If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
  • O indexador melhor do conjunto de indexadores do candidato é identificado usando as regras de resolução de sobrecarga de resolução de sobrecarga.The best indexer of the set of candidate indexers is identified using the overload resolution rules of Overload resolution. Se um único indexador melhor não pode ser identificado, o acesso do indexador é ambíguo e ocorre um erro em tempo de vinculação.If a single best indexer cannot be identified, the indexer access is ambiguous, and a binding-time error occurs.
  • As expressões de índice do argument_list são avaliados na ordem da esquerda para a direita.The index expressions of the argument_list are evaluated in order, from left to right. O resultado do processamento de acesso do indexador é uma expressão classificada como um acesso do indexador.The result of processing the indexer access is an expression classified as an indexer access. A expressão de acesso do indexador referencia o indexador determinado na etapa anterior e tem uma expressão de instância associada do P e uma lista de argumentos associados 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.

Dependendo do contexto no qual ele é usado, um acesso de indexador faz com que a invocação de um a acessador get ou o acessador set do indexador.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. Se o acesso do indexador é o destino de uma atribuição, o acessador set é chamado para atribuir um novo valor (atribuição simples).If the indexer access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). Em todos os outros casos, o acessador get é chamado para obter o valor atual (valores das expressões).In all other cases, the get accessor is invoked to obtain the current value (Values of expressions).

Esse acessoThis access

Um this_access consiste em uma palavra reservada this.A this_access consists of the reserved word this.

this_access
    : 'this'
    ;

Um this_access é permitido somente na bloco de um construtor de instância, um método de instância ou um acessador de instância.A this_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Ele tem um dos seguintes significados:It has one of the following meanings:

  • Quando this é usado em uma primary_expression dentro de um construtor de instância de uma classe, ele é classificado como um valor.When this is used in a primary_expression within an instance constructor of a class, it is classified as a value. O tipo do valor é o tipo de instância (o tipo de instância) da classe na qual ocorre o uso e o valor é uma referência ao objeto que está sendo construído.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.
  • Quando this é usado em uma primary_expression dentro de um método de instância ou o acessador de instância de uma classe, ele é classificado como um valor.When this is used in a primary_expression within an instance method or instance accessor of a class, it is classified as a value. O tipo do valor é o tipo de instância (o tipo de instância) da classe na qual ocorre o uso e o valor é uma referência ao objeto para o qual o método ou o acessador foi invocado.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.
  • Quando this é usado em uma primary_expression dentro de um construtor de instância de um struct, ele é classificado como uma variável.When this is used in a primary_expression within an instance constructor of a struct, it is classified as a variable. O tipo da variável é o tipo de instância (o tipo de instância) do struct no qual ocorre o uso e a variável representa a estrutura que está sendo construída.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. O this variável de um construtor de instância de um struct se comporta exatamente como um out parâmetro do tipo struct — em particular, isso significa que a variável deve ser definitivamente atribuída em cada caminho de execução da instância construtor.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.
  • Quando this é usado em uma primary_expression dentro de um método de instância ou o acessador de instância de um struct, ele é classificado como uma variável.When this is used in a primary_expression within an instance method or instance accessor of a struct, it is classified as a variable. O tipo da variável é o tipo de instância (o tipo de instância) do struct no qual ocorre o uso.The type of the variable is the instance type (The instance type) of the struct within which the usage occurs.
    • Se o método ou o acessador não é um iterador (iteradores), o this variável representa a estrutura para o qual o acessador ou método foi chamado e se comporta exatamente como um ref parâmetro do tipo 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.
    • Se o método ou o acessador é um iterador, o this variável representa uma cópia da estrutura para o qual o acessador ou método foi chamado e se comporta exatamente como um parâmetro de valor do tipo 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.

Uso de this em um primary_expression em um contexto diferente daqueles listados acima é um erro de tempo de compilação.Use of this in a primary_expression in a context other than the ones listed above is a compile-time error. Em particular, não é possível se referir this em um método estático, um acessador de propriedade estática, ou em um variable_initializer de uma declaração de campo.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.

Acesso de baseBase access

Um base_access consiste em uma palavra reservada base seguida por um "." token e um identificador ou um argument_list entre colchetes: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 ']'
    ;

Um base_access é usado para acessar membros de classe base que estão ocultos, da mesma forma nomeados membros na classe atual ou struct.A base_access is used to access base class members that are hidden by similarly named members in the current class or struct. Um base_access é permitido somente na bloco de um construtor de instância, um método de instância ou um acessador de instância.A base_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Quando base.I ocorre em uma classe ou struct, I deve indicar um membro da classe base dessa classe ou struct.When base.I occurs in a class or struct, I must denote a member of the base class of that class or struct. Da mesma forma, quando base[E] ocorre em uma classe, um indexador aplicável deve existir na classe base.Likewise, when base[E] occurs in a class, an applicable indexer must exist in the base class.

Em tempo de vinculação base_access expressões do formulário base.I e base[E] são avaliadas exatamente como se eles fossem escritos ((B)this).I e ((B)this)[E], onde B é a classe base da classe ou struct no qual ocorre a construção.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. Portanto, base.I e base[E] correspondem aos this.I e this[E], exceto this é visto como uma instância da classe 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.

Quando um base_access faz referência a um membro de função virtual (um método, propriedade ou indexador), a determinação de qual função de membro a ser invocado em tempo de execução (verificação de resolução de sobrecarga de dinâmica de tempo de compilação ) é alterado.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. O membro da função que é invocado é determinado pelo Localizando a implementação mais derivada (métodos virtuais) do membro da função em relação às B (em vez de em relação ao tipo de tempo de execução de this, como seria normal em um acesso de base não).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). Portanto, dentro de um override de um virtual membro da função, um base_access pode ser usado para chamar a implementação herdada do membro da função.Thus, within an override of a virtual function member, a base_access can be used to invoke the inherited implementation of the function member. Se o membro da função referenciado por uma base_access é abstrato, ocorrerá um erro em tempo de associação.If the function member referenced by a base_access is abstract, a binding-time error occurs.

Operadores de incremento e decremento pós-fixadosPostfix increment and decrement operators

post_increment_expression
    : primary_expression '++'
    ;

post_decrement_expression
    : primary_expression '--'
    ;

O operando de um incremento ou decremento pós-fixada operação deve ser uma expressão classificada como uma variável, um acesso de propriedade ou um acesso do indexador.The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. O resultado da operação é um valor do mesmo tipo como o operando.The result of the operation is a value of the same type as the operand.

Se o primary_expression tem o tipo de tempo de compilação dynamic e em seguida, o operador está dinamicamente vinculado (vinculação dinâmica), o post_increment_expressionou post_decrement_expression tem o tipo de tempo de compilação dynamic e as seguintes regras são aplicadas em tempo de execução usando o tipo de tempo de execução do 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.

Se o operando de um sufixo incrementar ou operação de decremento é uma propriedade ou o acesso do indexador, propriedade ou indexador deve ter uma get e um set acessador.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. Se isso não for o caso, ocorre um erro em tempo de vinculação.If this is not the case, a binding-time error occurs.

Resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicado para selecionar uma implementação do operador específico.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Predefinidas ++ e -- operadores existem para os seguintes tipos: sbyte, byte, short, ushort, int, uint, long, ulong, char , float, double, decimale qualquer tipo de enumeração.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Predefinido ++ operadores retornam o valor produzido pela adição de 1 para o operando e predefinido -- operadores retornam o valor produzido pela subtração de 1 de operando.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. Em um checked contexto, se o resultado dessa adição ou subtração está fora do intervalo do tipo de resultado e o tipo de resultado é um tipo integral ou um tipo de enumeração, um System.OverflowException é gerada.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.

O processamento de tempo de execução de um incremento ou decremento a operação do formulário x++ ou x-- consiste as seguintes etapas:The run-time processing of a postfix increment or decrement operation of the form x++ or x-- consists of the following steps:

  • Se x é classificado como uma variável:If x is classified as a variable:
    • x é avaliado para produzir a variável.x is evaluated to produce the variable.
    • O valor de x é salvo.The value of x is saved.
    • O operador selecionado é invocado com o valor salvo do x como seu argumento.The selected operator is invoked with the saved value of x as its argument.
    • O valor retornado pelo operador é armazenado no local fornecido pela avaliação de x.The value returned by the operator is stored in the location given by the evaluation of x.
    • O valor salvo do x se tornará o resultado da operação.The saved value of x becomes the result of the operation.
  • Se x é classificado como um acesso de propriedade ou indexador:If x is classified as a property or indexer access:
    • A expressão de instância (se x não é static) e a lista de argumentos (se x é um indexador de acesso) associadas com x são avaliados, e os resultados são usados em subsequente get e set invocações do acessador.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.
    • O get acessador de x é invocado e o valor retornado é salvo.The get accessor of x is invoked and the returned value is saved.
    • O operador selecionado é invocado com o valor salvo do x como seu argumento.The selected operator is invoked with the saved value of x as its argument.
    • O set acessador da x é invocado com o valor retornado pelo operador como seu value argumento.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • O valor salvo do x se tornará o resultado da operação.The saved value of x becomes the result of the operation.

O ++ e -- operadores também dão suporte a notação de prefixo (incremento de prefixo e operadores de decremento).The ++ and -- operators also support prefix notation (Prefix increment and decrement operators). Normalmente, o resultado de x++ ou x-- é o valor da x antes da operação, enquanto que o resultado da ++x ou --x é o valor do x após a operação.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. Em ambos os casos, x em si tem o mesmo valor após a operação.In either case, x itself has the same value after the operation.

Uma operator ++ ou operator -- implementação pode ser invocada usando a notação de prefixo ou sufixo.An operator ++ or operator -- implementation can be invoked using either postfix or prefix notation. Não é possível ter implementações de operadores separados para as duas notações.It is not possible to have separate operator implementations for the two notations.

O novo operadorThe new operator

O new operador é usado para criar novas instâncias de tipos.The new operator is used to create new instances of types.

Há três formas de new expressões:There are three forms of new expressions:

  • Expressões de criação de objeto são usadas para criar novas instâncias de tipos de classes e tipos de valor.Object creation expressions are used to create new instances of class types and value types.
  • Expressões de criação de matriz são usadas para criar novas instâncias dos tipos de matriz.Array creation expressions are used to create new instances of array types.
  • Expressões de criação de delegado são usadas para criar novas instâncias do representante de tipos.Delegate creation expressions are used to create new instances of delegate types.

O new operador implica a criação de uma instância de um tipo, mas não implica necessariamente alocação dinâmica de memória.The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. Em particular, instâncias de tipos de valor não exigem nenhuma memória adicional, além de variáveis em que eles residem, e nenhuma alocação de dinâmica ocorre quando new é usado para criar instâncias de tipos de valor.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.

Expressões de criação de objetoObject creation expressions

Uma object_creation_expression é usado para criar uma nova instância de um class_type ou uma 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
    ;

O tipo de uma object_creation_expression deve ser um class_type, um value_type ou uma type_parameter .The type of an object_creation_expression must be a class_type, a value_type or a type_parameter. O tipo não pode ser um abstract class_type.The type cannot be an abstract class_type.

Opcional argument_list (listas de argumentos) é permitido somente se o tipo é um class_type ou uma struct_ tipo.The optional argument_list (Argument lists) is permitted only if the type is a class_type or a struct_type.

Uma expressão de criação de objeto pode omitir a lista de argumentos de construtor e colocar parênteses fornecido inclui um inicializador de objeto ou um inicializador de coleção.An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. Omitir a lista de argumentos de construtor e colocando parênteses são equivalente a especificar uma lista de argumentos vazia.Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.

Processamento de uma expressão de criação de objeto que inclui um inicializador de objeto ou um inicializador de coleção consiste em processamento pela primeira vez o construtor de instância e, em seguida, processar as inicializações de membro ou o elemento especificadas pelo inicializador de objeto ( Inicializadores de objeto) ou o inicializador de coleção (inicializadores de coleção).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).

Se qualquer um dos argumentos opcionais argument_list tem o tipo de tempo de compilação dynamic o object_creation_expression associado dinamicamente (deassociaçãodinâmica) e as seguintes regras são aplicadas em tempo de execução usando o tipo de tempo de execução desses argumentos do argument_list que têm o tipo de tempo de compilação 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. No entanto, a criação do objeto sofre uma verificação de tempo de compilação limitada, conforme descrito em verificação de resolução de sobrecarga de dinâmica de tempo de compilação.However, the object creation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

O processamento de tempo de associação de um object_creation_expression do formulário new T(A), onde T é um class_type ou uma value_type e A é um recurso opcional argument_list, consiste as seguintes etapas: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:

  • Se T é um value_type e A não está presente:If T is a value_type and A is not present:
    • O object_creation_expression é uma invocação do construtor padrão.The object_creation_expression is a default constructor invocation. O resultado do object_creation_expression é um valor do tipo T, ou seja, o valor padrão para T conforme definido na ValueType o tipo.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.
  • Caso contrário, se T é um type_parameter e A não está presente:Otherwise, if T is a type_parameter and A is not present:
    • Se nenhuma restrição de tipo de valor ou uma restrição de construtor (restrições de parâmetro de tipo) foi especificado para T, ocorrerá um erro em tempo de associação.If no value type constraint or constructor constraint (Type parameter constraints) has been specified for T, a binding-time error occurs.
    • O resultado do object_creation_expression é um valor do tipo de tempo de execução que o parâmetro de tipo foi associado, ou seja, o resultado de chamar o construtor padrão desse tipo.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. O tipo de tempo de execução pode ser um tipo de referência ou um tipo de valor.The run-time type may be a reference type or a value type.
  • Caso contrário, se T é um class_type ou uma struct_type:Otherwise, if T is a class_type or a struct_type:
    • Se T é um abstract class_type, ocorre um erro de tempo de compilação.If T is an abstract class_type, a compile-time error occurs.
    • Para invocar o construtor de instância é determinado usando as regras de resolução de sobrecarga de resolução de sobrecarga.The instance constructor to invoke is determined using the overload resolution rules of Overload resolution. O conjunto de construtores de instância de candidato consiste em todos os construtores de instância acessível declarados em T que são aplicável em relação às A (membro da função aplicável).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). Se o conjunto de construtores de instância de release candidate está vazio ou se um construtor de instância única melhor não pode ser identificado, ocorrerá um erro de tempo de associação.If the set of candidate instance constructors is empty, or if a single best instance constructor cannot be identified, a binding-time error occurs.
    • O resultado do object_creation_expression é um valor do tipo T, ou seja, o valor produzido por invocar o construtor de instância determinado na etapa anterior.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.
  • Caso contrário, o object_creation_expression for inválido, um erro de tempo de associação.Otherwise, the object_creation_expression is invalid, and a binding-time error occurs.

Mesmo se o object_creation_expression é dinamicamente vinculado, o tipo de tempo de compilação é ainda T.Even if the object_creation_expression is dynamically bound, the compile-time type is still T.

O processamento de tempo de execução de um object_creation_expression do formulário new T(A), onde T está class_type ou uma struct_type e A é um recurso opcional argument_list, consiste as seguintes etapas: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:

  • Se T é um class_type:If T is a class_type:
    • Uma nova instância da classe T é alocado.A new instance of class T is allocated. Se não houver memória suficiente disponível para alocar a nova instância, um System.OutOfMemoryException é lançada e nenhuma outra etapa é executada.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • Todos os campos da nova instância são inicializados com seus valores padrão (valores padrão).All fields of the new instance are initialized to their default values (Default values).
    • O construtor de instância é invocado de acordo com as regras da invocação de membro de função (verificação de resolução de sobrecarga de dinâmica de tempo de compilação).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Uma referência à instância recentemente alocada automaticamente é passada para o construtor de instância e a instância pode ser acessada de dentro desse construtor como 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.
  • Se T é um struct_type:If T is a struct_type:
    • Uma instância do tipo T é criado ao alocar uma variável local temporária.An instance of type T is created by allocating a temporary local variable. Desde um construtor de instância de um struct_type é necessária, definitivamente, atribuir um valor para cada campo da instância que está sendo criado, nenhuma inicialização da variável temporária é necessária.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.
    • O construtor de instância é invocado de acordo com as regras da invocação de membro de função (verificação de resolução de sobrecarga de dinâmica de tempo de compilação).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Uma referência à instância recentemente alocada automaticamente é passada para o construtor de instância e a instância pode ser acessada de dentro desse construtor como 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.

Inicializadores de objetoObject initializers

Uma inicializador de objeto especifica valores para zero ou mais campos, propriedades ou elementos indexados de um objeto.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
    ;

Um inicializador de objeto consiste em uma sequência de inicializadores de membro, delimitados por { e } tokens e separados por vírgulas.An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas. Cada member_initializer designa um destino para a inicialização.Each member_initializer designates a target for the initialization. Uma identificador deve nomear um campo acessível ou uma propriedade do objeto que está sendo inicializado, enquanto um argument_list colocados entre colchetes deve especificar argumentos para um indexador acessível no objeto que está sendo inicializado.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. É um erro para um inicializador de objeto incluir mais de um inicializador de membro para o mesmo campo ou propriedade.It is an error for an object initializer to include more than one member initializer for the same field or property.

Cada initializer_target é seguido por um sinal de igual e uma expressão, um inicializador de objeto ou um inicializador de coleção.Each initializer_target is followed by an equals sign and either an expression, an object initializer or a collection initializer. Não é possível para expressões no inicializador de objeto para fazer referência ao objeto recém-criado que está sendo inicializado.It is not possible for expressions within the object initializer to refer to the newly created object it is initializing.

Um inicializador de membro que especifica uma expressão depois que o sinal de igual é processado da mesma maneira que uma atribuição (atribuição simples) para o destino.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.

Um inicializador de membro que especifica um inicializador de objeto após o sinal de igual é um inicializador de objeto aninhado, ou seja, uma inicialização de um objeto inserido.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. Em vez de atribuir um novo valor para o campo ou propriedade, as atribuições no inicializador de objeto aninhado são tratadas como atribuições aos membros do campo ou propriedade.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. Inicializadores de objeto aninhado não podem ser aplicados a propriedades com um tipo de valor, ou a campos somente leitura com um tipo de valor.Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.

Um inicializador de membro que especifica um inicializador de coleção após o sinal de igual é uma inicialização de uma coleção inserida.A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Em vez de atribuir uma nova coleção para o campo de destino, propriedade ou indexador, os elementos fornecidos no inicializador são adicionados à coleção referenciada pelo destino.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. O destino deve ser de um tipo de coleção que atende aos requisitos especificados em inicializadores de coleção.The target must be of a collection type that satisfies the requirements specified in Collection initializers.

Os argumentos para um inicializador de índice sempre serão avaliados exatamente uma vez.The arguments to an index initializer will always be evaluated exactly once. Portanto, mesmo se os argumentos acabam nunca sendo usado (por exemplo, devido a um inicializador vazio aninhado), eles serão avaliados por seus efeitos colaterais.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.

A classe a seguir representa um ponto com duas coordenadas: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; } }
}

Uma instância de Point pode ser criado e inicializado da seguinte maneira:An instance of Point can be created and initialized as follows:

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

que tem o mesmo efeito quewhich has the same effect as

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

onde __a é uma variável temporária caso contrário, invisível e inacessível.where __a is an otherwise invisible and inaccessible temporary variable. A classe a seguir representa um retângulo criado a partir de dois pontos: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; } }
}

Uma instância de Rectangle pode ser criado e inicializado da seguinte maneira: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 }
};

que tem o mesmo efeito 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;

em que __r, __p1 e __p2 são variáveis temporárias que estariam invisíveis e inacessíveis.where __r, __p1 and __p2 are temporary variables that are otherwise invisible and inaccessible.

Se Rectangledo construtor aloca os dois inseridos Point instânciasIf 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; } }
}

a construção a seguir pode ser usada para inicializar o embedded Point instâncias em vez de atribuir novas instâncias: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 }
};

que tem o mesmo efeito 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;

Dada uma definição de apropriada de C, o exemplo a seguir: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] = {}
};

é equivalente a esta série de atribuições de: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;

onde __c, etc., são geradas variáveis que são invisíveis e inacessíveis para o código-fonte.where __c, etc., are generated variables that are invisible and inaccessible to the source code. Observe que os argumentos para [0,0] são avaliada apenas uma vez e os argumentos para [1,2] são avaliadas uma vez, mesmo que eles nunca são usados.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.

Inicializadores de coleçãoCollection initializers

Um inicializador de coleção Especifica os elementos de uma coleção.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)*
    ;

Um inicializador de coleção consiste em uma sequência de inicializadores de elemento, entre { e } tokens e separados por vírgulas.A collection initializer consists of a sequence of element initializers, enclosed by { and } tokens and separated by commas. Cada inicializador de elemento Especifica um elemento a ser adicionado ao objeto de coleção que está sendo inicializado e consiste em uma lista de expressões entre { e } tokens e separados por vírgulas.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. Um inicializador de elemento de expressão única pode ser escrito sem as chaves, mas, em seguida, não pode ser uma expressão de atribuição, para evitar ambiguidade com inicializadores de membro.A single-expression element initializer can be written without braces, but cannot then be an assignment expression, to avoid ambiguity with member initializers. O non_assignment_expression produção é definida no expressão.The non_assignment_expression production is defined in Expression.

Este é um exemplo de uma expressão de criação de objeto que inclui um inicializador de coleção: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 };

O objeto de coleção ao qual um inicializador de coleção é aplicado deve ser de um tipo que implementa System.Collections.IEnumerable ou ocorre um erro de tempo de compilação.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. Para cada elemento na ordem, o inicializador de coleção invoca um Add método no destino do objeto com a lista de expressões do inicializador de elemento como a lista de argumentos, aplicação de pesquisa de membro normal e resolução para cada invocação de sobrecarga.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. Portanto, o objeto de coleção deve ter um método de instância ou extensão aplicável, com o nome Add para cada inicializador de elemento.Thus, the collection object must have an applicable instance or extension method with the name Add for each element initializer.

A classe a seguir representa um contato com um nome e uma lista de números de telefone: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; } }
}

Um List<Contact> pode ser criado e inicializado da seguinte maneira: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" }
    }
};

que tem o mesmo efeito 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;

em que __clist, __c1 e __c2 são variáveis temporárias que estariam invisíveis e inacessíveis.where __clist, __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.

Expressões de criação de matrizArray creation expressions

Uma array_creation_expression é usado para criar uma nova instância de um 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
    ;

Uma expressão de criação de matriz do primeiro formulário aloca uma instância de matriz do tipo que é o resultado da exclusão de cada uma das expressões individuais da lista de expressões.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. Por exemplo, a expressão de criação de matriz new int[10,20] produz uma instância de matriz do tipo int[,]e a expressão de criação de matriz new int[10][,] produz uma matriz do tipo 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[][,]. Cada expressão na lista da expressão deve ser do tipo int, uint, long, ou ulong, ou implicitamente conversível em um ou mais desses tipos.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. O valor de cada expressão determina o comprimento da dimensão correspondente na instância de matriz recém-alocada.The value of each expression determines the length of the corresponding dimension in the newly allocated array instance. Como o comprimento de uma dimensão de matriz deve ser não negativo, ele é um erro de tempo de compilação para ter uma constant_expression com um valor negativo na lista de expressões.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.

Exceto em um contexto sem segurança (contextos não seguros), o layout de matrizes não é especificado.Except in an unsafe context (Unsafe contexts), the layout of arrays is unspecified.

Se uma expressão de criação de matriz do primeiro formulário inclui um inicializador de matriz, cada expressão na lista da expressão deve ser uma constante e os comprimentos de dimensão e de classificação especificados pela lista de expressão devem corresponder do inicializador de matriz.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.

Em uma expressão de criação de matriz no formato de segundo ou terceiro, a classificação do especificador de tipo ou a classificação de matriz especificado deve corresponder do inicializador de matriz.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. Os comprimentos de dimensão individuais são inferidos do número de elementos em cada um dos níveis de aninhamento correspondentes do inicializador de matriz.The individual dimension lengths are inferred from the number of elements in each of the corresponding nesting levels of the array initializer. Assim, a expressãoThus, the expression

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

corresponde exatamente aoexactly corresponds to

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

Uma expressão de criação de matriz do terceiro formulário é conhecida como um expressão de criação de matriz de tipo implícito.An array creation expression of the third form is referred to as an implicitly typed array creation expression. Ele é semelhante ao segundo formato, exceto que o tipo de elemento da matriz não for explicitamente fornecido, mas é determinado como o tipo mais comum (localizando o melhor tipo comum de um conjunto de expressões) do conjunto de expressões na matriz inicializador.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. Para uma matriz multidimensional, ou seja, aquele em que o rank_specifier contém pelo menos uma vírgula, este conjunto consiste em todos expressãos encontrado no aninhados array_initializers.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.

Inicializadores de matriz são descritos mais detalhadamente em inicializadores de matriz.Array initializers are described further in Array initializers.

O resultado da avaliação de uma expressão de criação de matriz é classificado como um valor, ou seja, uma referência para a instância de matriz recém-alocada.The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. O processamento de tempo de execução de uma expressão de criação de matriz consiste as seguintes etapas:The run-time processing of an array creation expression consists of the following steps:

  • As expressões de comprimento da dimensão do lista_de_expressão são avaliados na ordem da esquerda para a direita.The dimension length expressions of the expression_list are evaluated in order, from left to right. Após a avaliação de cada expressão, uma conversão implícita (conversões implícitas) é executada para um dos seguintes tipos: 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. O primeiro tipo nessa lista para o qual existe uma conversão implícita é escolhido.The first type in this list for which an implicit conversion exists is chosen. Se a avaliação de uma expressão ou a conversão implícita subsequente faz com que uma exceção, não há mais expressões são avaliadas, e nenhuma outra etapa é executada.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.
  • Os valores computados para os tamanhos da dimensão são validados da seguinte maneira.The computed values for the dimension lengths are validated as follows. Se um ou mais dos valores são menor que zero, um System.OverflowException é lançada e nenhuma outra etapa é executada.If one or more of the values are less than zero, a System.OverflowException is thrown and no further steps are executed.
  • Uma instância de matriz com os comprimentos de determinada dimensão é alocada.An array instance with the given dimension lengths is allocated. Se não houver memória suficiente disponível para alocar a nova instância, um System.OutOfMemoryException é lançada e nenhuma outra etapa é executada.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
  • Todos os elementos da nova instância de matriz são inicializados com seus valores padrão (valores padrão).All elements of the new array instance are initialized to their default values (Default values).
  • Se a expressão de criação de matriz contiver um inicializador de matriz, cada expressão de inicializador de matriz é avaliada e atribuída ao seu elemento correspondente da matriz.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. As atribuições e avaliações são executadas na ordem em que as expressões são gravadas no inicializador de matriz — em outras palavras, os elementos são inicializados em índice ordem crescente, com a dimensão mais à direita, aumentando pela primeira vez.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. Se a avaliação de uma determinada expressão ou atribuição subsequente para o elemento de matriz correspondente faz com que uma exceção, em seguida, sem elementos adicionais são inicializados (e os elementos restantes, portanto, terão seus valores padrão).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).

Uma expressão de criação de matriz permite a instanciação de uma matriz com elementos de um tipo de matriz, mas os elementos de como uma matriz devem ser inicializados manualmente.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. Por exemplo, a instruçãoFor example, the statement

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

cria uma matriz unidimensional com 100 elementos do tipo int[].creates a single-dimensional array with 100 elements of type int[]. O valor inicial de cada elemento é null.The initial value of each element is null. Não é possível para a mesma expressão de criação de matriz para também criar uma instância de submatrizes e a instruçãoIt 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

resultados em um erro de tempo de compilação.results in a compile-time error. Instanciação de subpropriedades matrizes em vez disso, deve ser executada manualmente, como emInstantiation 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];

Quando uma matriz de matrizes tem um formato "retangular", ou seja, quando as matrizes de subpropriedades são todos do mesmo comprimento, é mais eficiente usar uma matriz multidimensional.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. No exemplo acima, a instanciação da matriz de matrizes cria 101 objetos — uma matriz externa e submatrizes de 100.In the example above, instantiation of the array of arrays creates 101 objects—one outer array and 100 sub-arrays. Por outro lado,In contrast,

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

cria apenas um único objeto, uma matriz bidimensional e realiza a alocação em uma única instrução.creates only a single object, a two-dimensional array, and accomplishes the allocation in a single statement.

A seguir estão exemplos de expressões de criação de matriz de tipo implícito: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

A última expressão causa um erro de tempo de compilação porque nem int nem string é implicitamente conversível para o outro e, em seguida, digite aqui é não é mais comum.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. Uma expressão de criação de matriz tipada explicitamente deve ser usada nesse caso, por exemplo, especificando o tipo a ser object[].An explicitly typed array creation expression must be used in this case, for example specifying the type to be object[]. Como alternativa, um dos elementos pode ser convertido em um tipo de base comum, que, em seguida, iria se tornar o tipo do elemento deduzido.Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.

Expressões de criação de matriz implícita podem ser combinadas com inicializadores de objeto anônimos (expressões de criação de objeto anônimo) criar anonimamente digitado estruturas de dados.Implicitly typed array creation expressions can be combined with anonymous object initializers (Anonymous object creation expressions) to create anonymously typed data structures. Por exemplo: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" }
    }
};

Expressões de criação de delegadoDelegate creation expressions

Um delegate_creation_expression é usado para criar uma nova instância de um delegate_type.A delegate_creation_expression is used to create a new instance of a delegate_type.

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

O argumento de uma expressão de criação de delegado deve ser um grupo de método, uma função anônima ou um valor de tipo de tempo de compilação dynamic ou um 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. Se o argumento for um grupo de métodos, ele identifica o método e, para um método de instância, o objeto para o qual criar um delegado.If the argument is a method group, it identifies the method and, for an instance method, the object for which to create a delegate. Se o argumento for uma função anônima diretamente define os parâmetros e o corpo do método de destino de delegado.If the argument is an anonymous function it directly defines the parameters and method body of the delegate target. Se o argumento for um valor que identifica uma instância de delegado do qual criar uma cópia.If the argument is a value it identifies a delegate instance of which to create a copy.

Se o expressão tem o tipo de tempo de compilação dynamic, o delegate_creation_expression associado dinamicamente (vinculação dinâmica) e as regras abaixo são aplicadas em tempo de execução usando o tipo de tempo de execução do expressão.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. Caso contrário, as regras são aplicadas em tempo de compilação.Otherwise the rules are applied at compile-time.

O processamento de tempo de associação de um delegate_creation_expression do formulário new D(E), onde D é um delegate_type e E é uma expressão , consiste as seguintes etapas: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:

  • Se E é um grupo de método, a expressão de criação de delegado é processada da mesma forma como a conversão de grupos de método (conversões de grupo de método) de E para 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.
  • Se E é uma função anônima, a expressão de criação de delegado é processada da mesma forma como uma conversão de função anônima (conversões de função anônima) de E para 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.
  • Se E é um valor E devem ser compatíveis (declarações de delegado) com D, e o resultado é uma referência a um delegado recém-criado do tipo D que se refere à invocação do mesma Listar como 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. Se E não é compatível com D, ocorre um erro de tempo de compilação.If E is not compatible with D, a compile-time error occurs.

O processamento de tempo de execução de um delegate_creation_expression do formulário new D(E), onde D é um delegate_type e E é uma expressão , consiste as seguintes etapas: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:

  • Se E é um grupo de método, a expressão de criação de delegado é avaliada como uma conversão de grupo de método (conversões de grupo de método) de E para 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.
  • Se E é uma função anônima, a criação de delegado é avaliada como uma conversão de função anônima da E à D (conversões de função anônima).If E is an anonymous function, the delegate creation is evaluated as an anonymous function conversion from E to D (Anonymous function conversions).
  • Se E é um valor de uma delegate_type:If E is a value of a delegate_type:
    • E é avaliado.E is evaluated. Se essa avaliação causa uma exceção, nenhuma outra etapa é executada.If this evaluation causes an exception, no further steps are executed.
    • Se o valor de E está null, um System.NullReferenceException é lançada e nenhuma outra etapa é executada.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Uma nova instância do tipo de delegado D é alocado.A new instance of the delegate type D is allocated. Se não houver memória suficiente disponível para alocar a nova instância, um System.OutOfMemoryException é lançada e nenhuma outra etapa é executada.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • A nova instância de delegado é inicializada com a mesma lista de invocação que a instância do representante fornecida pelo E.The new delegate instance is initialized with the same invocation list as the delegate instance given by E.

A lista de invocação de um delegado é determinada quando o delegado é instanciado e, em seguida, é uma constante para o tempo de vida inteiro do delegado.The invocation list of a delegate is determined when the delegate is instantiated and then remains constant for the entire lifetime of the delegate. Em outras palavras, não é possível alterar as entidades de destino que pode ser chamado de um delegado após ele ter sido criado.In other words, it is not possible to change the target callable entities of a delegate once it has been created. Quando dois delegados são combinados ou um for removido de outra (declarações de delegado), faz com que um novo delegado; nenhum delegado existente tem seu conteúdo alterado.When two delegates are combined or one is removed from another (Delegate declarations), a new delegate results; no existing delegate has its contents changed.

Não é possível criar um delegado que faz referência a uma propriedade, indexador, operador definido pelo usuário, construtor de instância, destruidor ou construtor estático.It is not possible to create a delegate that refers to a property, indexer, user-defined operator, instance constructor, destructor, or static constructor.

Conforme descrito acima, quando um delegado é criado de um grupo de método, a lista de parâmetros formais e tipo de retorno do delegado de determinar quais métodos sobrecarregados para selecionar.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. No exemploIn 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;
    }
}

o A.f campo é inicializado com um delegado que se refere à segunda Square método porque esse método corresponde exatamente a lista de parâmetros formais e o tipo de retorno 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. Tinha o segundo Square método não estado presente, um erro de tempo de compilação teria ocorrido.Had the second Square method not been present, a compile-time error would have occurred.

Expressões de criação de objeto anônimoAnonymous object creation expressions

Uma anonymous_object_creation_expression é usado para criar um objeto de um tipo anônimo.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
    ;

Um inicializador de objeto anônimos declara um tipo anônimo e retorna uma instância desse tipo.An anonymous object initializer declares an anonymous type and returns an instance of that type. Um tipo anônimo é um tipo sem nome de classe que herda diretamente de object.An anonymous type is a nameless class type that inherits directly from object. Os membros de um tipo anônimo são uma sequência de propriedades somente leitura inferidos do inicializador de objeto anônimo usado para criar uma instância do tipo.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. Especificamente, um inicializador de objeto anônimo do formulárioSpecifically, an anonymous object initializer of the form

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

declara um tipo anônimo do formuláriodeclares 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() { ... }
}

em que cada Tx é o tipo da expressão correspondente ex.where each Tx is the type of the corresponding expression ex. A expressão usada em uma member_declarator deve ter um tipo.The expression used in a member_declarator must have a type. Portanto, é um erro de tempo de compilação para uma expressão em uma member_declarator ser null ou uma função anônima.Thus, it is a compile-time error for an expression in a member_declarator to be null or an anonymous function. Também é um erro de tempo de compilação para a expressão ter um tipo que não é seguro.It is also a compile-time error for the expression to have an unsafe type.

Os nomes de um tipo anônimo e do parâmetro a seu Equals método são gerados automaticamente pelo compilador e não pode ser referenciado no texto do programa.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.

Dentro do mesmo programa, dois inicializadores de objeto anônimos que especificam uma sequência de propriedades dos mesmos nomes e tipos de tempo de compilação na mesma ordem produzirá instâncias do mesmo tipo anônimo.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.

No exemploIn the example

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

a atribuição na última linha é permitida porque p1 e p2 são do mesmo tipo anônimo.the assignment on the last line is permitted because p1 and p2 are of the same anonymous type.

O Equals e GetHashcode métodos em tipos anônimos substituir os métodos herdados da objecte são definidos em termos do Equals e GetHashcode das propriedades, para que duas instâncias do mesmo tipo anônimo são iguais se e apenas se todas as suas propriedades são iguais.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.

Um Declarador de membro pode ser abreviado como um nome simples (inferência), um acesso de membro (verificação de resolução de sobrecarga de dinâmica de tempo de compilação), um acesso de base (deacessodeBase) ou um acesso de membro condicional nulo (expressões condicionais nulos como inicializadores de projeção).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). Isso é chamado de um inicializadores de projeção e é uma abreviação para uma declaração de e a atribuição a uma propriedade com o mesmo nome.This is called a projection initializer and is shorthand for a declaration of and assignment to a property with the same name. Especificamente, os declaradores de membro dos formuláriosSpecifically, member declarators of the forms

identifier
expr.identifier

são exatamente equivalentes às seguintes, respectivamente:are precisely equivalent to the following, respectively:

identifier = identifier
identifier = expr.identifier

Assim, em inicializadores de projeção a identificador seleciona tanto o valor e o campo ou propriedade à qual o valor é atribuído.Thus, in a projection initializer the identifier selects both the value and the field or property to which the value is assigned. Intuitivamente, um inicializador de projeção projetos não apenas um valor, mas também o nome do valor.Intuitively, a projection initializer projects not just a value, but also the name of the value.

O operador typeofThe typeof operator

O typeof operador é usado para obter o System.Type objeto para um tipo.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
    : ','
    ;

A primeira forma de typeof_expression consiste em um typeof seguido por um parênteses de palavra-chave tipo.The first form of typeof_expression consists of a typeof keyword followed by a parenthesized type. O resultado de uma expressão desse formulário é o System.Type objeto para o tipo indicado.The result of an expression of this form is the System.Type object for the indicated type. Há apenas um System.Type objeto para qualquer tipo determinado.There is only one System.Type object for any given type. Isso significa que, para um tipo T, typeof(T) == typeof(T) é sempre verdadeiro.This means that for a type T, typeof(T) == typeof(T) is always true. O tipo não pode ser dynamic.The type cannot be dynamic.

A segunda forma de typeof_expression consiste em um typeof seguido por um parênteses de palavra-chave unbound_type_name.The second form of typeof_expression consists of a typeof keyword followed by a parenthesized unbound_type_name. Uma unbound_type_name é muito semelhante a um type_name (nomes de Namespace e tipo), exceto que um unbound_type_name contém generic_dimension_specifiers em que um type_name contém 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. Quando o operando de um typeof_expression é uma sequência de tokens que satisfaça as gramáticas de ambos unbound_type_name e type_name, ou seja, quando ele não contém nem uma generic_dimension_specifier nem um type_argument_list, a sequência de tokens é considerada um 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. O significado de um unbound_type_name é determinado da seguinte maneira:The meaning of an unbound_type_name is determined as follows:

  • Converter a sequência de tokens para um type_name , substituindo cada generic_dimension_specifier com um type_argument_list tendo o mesmo número de vírgulas e o palavra-chave object à medida que cada 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.
  • Avaliar resultante type_name, ignorando todas as restrições de parâmetro de tipo.Evaluate the resulting type_name, while ignoring all type parameter constraints.
  • O unbound_type_name resolve para o tipo genérico não associado, associado com o tipo construído resultante (associado e não associados a tipos).The unbound_type_name resolves to the unbound generic type associated with the resulting constructed type (Bound and unbound types).

O resultado do typeof_expression é o System.Type objeto resultante não associado de tipo genérico.The result of the typeof_expression is the System.Type object for the resulting unbound generic type.

O terceiro formulário da typeof_expression consiste em um typeof palavra-chave, seguido por um entre parênteses void palavra-chave.The third form of typeof_expression consists of a typeof keyword followed by a parenthesized void keyword. O resultado de uma expressão desse formulário é o System.Type objeto que representa a ausência de um tipo.The result of an expression of this form is the System.Type object that represents the absence of a type. O objeto do tipo retornado por typeof(void) é diferente do tipo objeto retornado para qualquer tipo.The type object returned by typeof(void) is distinct from the type object returned for any type. Esse objeto de tipo especial é útil em bibliotecas de classes que permitem que a reflexão para métodos no idioma, em que esses métodos deverão ter uma forma de representar o tipo de retorno de qualquer método, incluindo métodos void, com uma instância do 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.

O typeof operador pode ser usado em um parâmetro de tipo.The typeof operator can be used on a type parameter. O resultado é o System.Type objeto para o tipo de tempo de execução que estava associado ao parâmetro de tipo.The result is the System.Type object for the run-time type that was bound to the type parameter. O typeof operador também pode ser usado em um tipo construído ou um tipo genérico não associado (ligado e não associados a tipos de).The typeof operator can also be used on a constructed type or an unbound generic type (Bound and unbound types). O System.Type do objeto para um tipo genérico não associado não é igual a System.Type objeto do tipo de instância.The System.Type object for an unbound generic type is not the same as the System.Type object of the instance type. O tipo de instância é sempre um tipo construído fechado em tempo de execução para sua System.Type objeto depende dos argumentos de tipo de tempo de execução em uso, enquanto o tipo genérico não associado não tiver nenhum argumento de tipo.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.

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

produz a seguinte saída: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]

Observe que int e System.Int32 são do mesmo tipo.Note that int and System.Int32 are the same type.

Observe também que o resultado de typeof(X<>) não requer que o argumento de tipo, mas o resultado de typeof(X<T>) faz.Also note that the result of typeof(X<>) does not depend on the type argument but the result of typeof(X<T>) does.

Os operadores verificados e não verificadosThe checked and unchecked operators

O checked e unchecked operadores são usados para controlar a contexto de verificação de estouro para conversões e operações aritméticas de tipo integral.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 ')'
    ;

O checked operador avalia a expressão contida em um contexto verificado e o unchecked operador avalia a expressão contida em um contexto desmarcado.The checked operator evaluates the contained expression in a checked context, and the unchecked operator evaluates the contained expression in an unchecked context. Um checked_expression ou unchecked_expression corresponde exatamente um parenthesized_expression (asexpressõesentreparênteses), exceto que a expressão contida é avaliada no contexto de verificação de estouro determinado.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.

O contexto de verificação de estouro também pode ser controlado por meio de checked e unchecked instruções (as instruções checked e unchecked).The overflow checking context can also be controlled through the checked and unchecked statements (The checked and unchecked statements).

As seguintes operações são afetadas pelo contexto estabelecido de verificação de estouro de checked e unchecked operadores e as instruções:The following operations are affected by the overflow checking context established by the checked and unchecked operators and statements:

Quando uma das operações acima produzir um resultado que é muito grande para ser representado no tipo de destino, o contexto no qual a operação é executados controles o comportamento resultante: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:

  • Em um checked contexto, se a operação for uma expressão de constante (expressões constantes), ocorre um erro de tempo de compilação.In a checked context, if the operation is a constant expression (Constant expressions), a compile-time error occurs. Caso contrário, quando a operação é executada em tempo de execução, um System.OverflowException é gerada.Otherwise, when the operation is performed at run-time, a System.OverflowException is thrown.
  • Em um unchecked contexto, o resultado é truncado descartando quaisquer bits de ordem superior que não cabem no tipo de destino.In an unchecked context, the result is truncated by discarding any high-order bits that do not fit in the destination type.

Para expressões não constantes (expressões são avaliadas em tempo de execução) que não são incluídos por qualquer checked ou unchecked operadores ou mais instruções, o contexto de verificação de estouro de padrão é unchecked , a menos que os fatores de externo (por exemplo, o compilador comutadores e configuração do ambiente de execução) chamam para checked avaliação.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.

Para expressões de constante (expressões que podem ser completamente avaliadas em tempo de compilação), o contexto de verificação de estouro de padrão sempre é checked.For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. A menos que uma expressão de constante seja explicitamente colocada em um unchecked contexto, estouros que ocorrem durante a avaliação do tempo de compilação da expressão sempre causam erros de tempo de compilação.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.

O corpo de uma função anônima não é afetado pelas checked ou unchecked contextos em que a função anônima ocorre.The body of an anonymous function is not affected by checked or unchecked contexts in which the anonymous function occurs.

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

Nenhum erro de tempo de compilação é relatado, pois nenhuma das expressões pode ser avaliada em tempo de compilação.no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. Em tempo de execução, o F método lança um System.OverflowExceptione o G método retorna-727379968 (os 32 bits inferiores do resultado fora do intervalo).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). O comportamento do H método depende do contexto para a compilação de verificação de estouro de padrão, mas é o mesmo que F ou o mesmo que 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.

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

os estouros ocorridos durante a avaliação das expressões constantes na F e H causar erros de tempo de compilação a ser relatado porque as expressões são avaliadas em um checked contexto.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. Um estouro também ocorre ao avaliar a expressão de constante G, mas já que a avaliação é feita em um unchecked contexto, o estouro não será relatado.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.

O checked e unchecked operadores afetam apenas o contexto para as operações que estão contidos textualmente de verificação de estouro de "("e")" tokens.The checked and unchecked operators only affect the overflow checking context for those operations that are textually contained within the "(" and ")" tokens. Os operadores não têm efeito nos membros da função que são invocados como resultado da avaliação da expressão independente.The operators have no effect on function members that are invoked as a result of evaluating the contained expression. No exemploIn the example

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

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

o uso de checked na F não afeta a avaliação de x * y na Multiply, então x * y é avaliada no contexto de verificação de estouro de padrão.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.

O unchecked operador é conveniente ao escrever constantes dos tipos integrais com sinal em notação hexadecimal.The unchecked operator is convenient when writing constants of the signed integral types in hexadecimal notation. Por exemplo:For example:

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

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

Ambas as constantes hexadecimais acima são do tipo uint.Both of the hexadecimal constants above are of type uint. Como as constantes são fora o int de intervalo, sem a unchecked operador, as conversões para int geraria erros de tempo de compilação.Because the constants are outside the int range, without the unchecked operator, the casts to int would produce compile-time errors.

O checked e unchecked operadores e as instruções permitem que os programadores controlar determinados aspectos de alguns cálculos numéricos.The checked and unchecked operators and statements allow programmers to control certain aspects of some numeric calculations. No entanto, o comportamento de alguns operadores numéricos depende de tipos de dados de seus operandos.However, the behavior of some numeric operators depends on their operands' data types. Por exemplo, a multiplicação de duas casas decimais sempre resulta em uma exceção no estouro, mesmo dentro um explicitamente unchecked construir.For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked construct. Da mesma forma, a multiplicação de dois floats nunca resultados em uma exceção no estouro até mesmo dentro um explicitamente checked construir.Similarly, multiplying two floats never results in an exception on overflow even within an explicitly checked construct. Além disso, outros operadores nunca são afetados pelo modo de verificação, se padrão ou explícita.In addition, other operators are never affected by the mode of checking, whether default or explicit.

Expressões de valor padrãoDefault value expressions

Uma expressão de valor padrão é usada para obter o valor padrão (valores padrão) de um tipo.A default value expression is used to obtain the default value (Default values) of a type. Normalmente, uma expressão de valor padrão é usada para parâmetros de tipo, desde que ele pode não ser conhecido se o parâmetro de tipo é um tipo de valor ou um tipo de referência.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. (Não existe conversão do null literal a um parâmetro de tipo, a menos que o parâmetro de tipo é conhecido por ser um tipo de referência.)(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 ')'
    ;

Se o tipo em um default_value_expression é avaliada em tempo de execução para um tipo de referência, o resultado é null convertido nesse tipo.If the type in a default_value_expression evaluates at run-time to a reference type, the result is null converted to that type. Se o tipo em um default_value_expression é avaliada em tempo de execução para um tipo de valor, o resultado é o value_typedo valor padrão (padrão construtores).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).

Um default_value_expression é uma expressão constante (expressões constantes) se o tipo é um tipo de referência ou um parâmetro de tipo é conhecido por ser um tipo de referência (parâmetro de tipo restrições de).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). Além disso, uma default_value_expression é uma expressão constante, se o tipo é um dos seguintes tipos de valor: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, ou qualquer tipo de enumeração.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.

Expressões NameofNameof expressions

Um nameof_expression é usado para obter o nome de uma entidade programa como uma cadeia de caracteres 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
    ;

Gramaticalmente falando, o named_entity operando sempre é uma expressão.Grammatically speaking, the named_entity operand is always an expression. Porque nameof não é uma palavra-chave reservada, a expressão nameof sempre é sintaticamente ambígua com uma invocação do nome simple nameof.Because nameof is not a reserved keyword, a nameof expression is always syntactically ambiguous with an invocation of the simple name nameof. Por razões de compatibilidade, se uma pesquisa de nome (nomes simples) de nome nameof for bem-sucedida, a expressão é tratada como um invocation_expression – independentemente de se a invocação é legal.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. Caso contrário, ele é um nameof_expression.Otherwise it is a nameof_expression.

O significado do named_entity de uma nameof_expression é o significado de-lo como uma expressão; ou seja, tanto como um simple_name, um base_access ou um 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. No entanto, em que a pesquisa descrito em nomes simples e acesso de membro resulta em um erro porque um membro de instância foi encontrado em um contexto estático, uma nameof_expressionnão produz nenhum esse erro.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.

É um erro de tempo de compilação para um named_entity designar um grupo de métodos para ter um type_argument_list.It is a compile-time error for a named_entity designating a method group to have a type_argument_list. É um erro de tempo de compilação para um named_entity_target para ter o tipo dynamic.It is a compile time error for a named_entity_target to have the type dynamic.

Um nameof_expression é uma expressão constante do tipo string, e não tem nenhum efeito em tempo de execução.A nameof_expression is a constant expression of type string, and has no effect at runtime. Especificamente, sua named_entity não será avaliada e é ignorada para fins de análise de atribuição definitiva (regras gerais para expressões simples).Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). Seu valor é o último identificador do named_entity antes do final opcional type_argument_list, transformada da seguinte maneira:Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed in the following way:

  • O prefixo "@", se usado, é removido.The prefix "@", if used, is removed.
  • Cada unicode_escape_sequence é transformado em seu caractere Unicode correspondente.Each unicode_escape_sequence is transformed into its corresponding Unicode character.
  • Qualquer formatting_characters são removidos.Any formatting_characters are removed.

Essas são as mesmas transformações aplicadas na identificadores ao testar a igualdade entre identificadores.These are the same transformations applied in Identifiers when testing equality between identifiers.

TODO: exemplosTODO: examples

Expressões de método anônimoAnonymous method expressions

Uma anonymous_method_expression é uma das duas maneiras de definir uma função anônima.An anonymous_method_expression is one of two ways of defining an anonymous function. Além disso, elas são descritas em expressões de função anônima.These are further described in Anonymous function expressions.

Operadores unáriosUnary operators

O ?, +, -, !, ~, ++, --, converta, e await os operadores unários são chamados de operadores.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
    ;

Se o operando de um unary_expression tem o tipo de tempo de compilação dynamic, ele está vinculado dinamicamente (vinculação dinâmica).If the operand of a unary_expression has the compile-time type dynamic, it is dynamically bound (Dynamic binding). Nesse caso, o tempo de compilação de tipo dos unary_expression é dynamic, e a resolução descrita a seguir ocorrerá em tempo de execução usando o tipo de tempo de execução do operando.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.

Operador nulo condicionalNull-conditional operator

O operador nulo condicional se aplica uma lista das operações ao operando somente se o operando não for nulo.The null-conditional operator applies a list of operations to its operand only if that operand is non-null. Caso contrário, o resultado da aplicação do operador é 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? ')'
    ;

A lista de operações pode incluir acesso de membro e operações de acesso de elemento (que podem estar nulo-condicional), bem como invocação.The list of operations can include member access and element access operations (which may themselves be null-conditional), as well as invocation.

Por exemplo, a expressão a.b?[0]?.c() é um null_conditional_expression com um primary_expression a.b e null_conditional_operations ?[0] (acesso de elemento nulo-condicional), ?.c (acesso de membro nulo condicional) e () (invocação).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).

Para um null_conditional_expression E com um primary_expression P, permitem que E0 ser a expressão obtida removendo textualmente o entrelinhamento ?de cada um dos null_conditional_operations de E que tiver uma.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. Conceitualmente, E0 é a expressão que será avaliada se nenhum das verificações nulas representado pela ?s encontrar um null.Conceptually, E0 is the expression that will be evaluated if none of the null checks represented by the ?s do find a null.

Além disso, permitir que E1 ser a expressão obtida removendo textualmente o entrelinhamento ? de apenas o primeiro a null_conditional_operations em E.Also, let E1 be the expression obtained by textually removing the leading ? from just the first of the null_conditional_operations in E. Isso pode levar a um primary-expression (se houver apenas um ?) ou para outro null_conditional_expression.This may lead to a primary-expression (if there was just one ?) or to another null_conditional_expression.

Por exemplo, se E é a expressão a.b?[0]?.c(), em seguida, E0 é a expressão a.b[0].c() e E1 é a expressão 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().

Se E0 é classificado como nothing, em seguida, E é classificado como nada.If E0 is classified as nothing, then E is classified as nothing. Caso contrário, E é classificado como um valor.Otherwise E is classified as a value.

E0 e E1 são usados para determinar o significado de E:E0 and E1 are used to determine the meaning of E:

  • Se E ocorre como uma statement_expression o significado de E é o mesmo que a instruçãoIf E occurs as a statement_expression the meaning of E is the same as the statement

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

    exceto que P é avaliada apenas uma vez.except that P is evaluated only once.

  • Caso contrário, se E0 é classificado como nada ocorre um erro de tempo de compilação.Otherwise, if E0 is classified as nothing a compile-time error occurs.

  • Caso contrário, deixe T0 ser o tipo de E0.Otherwise, let T0 be the type of E0.

    • Se T0 é um parâmetro de tipo que não sejam conhecido por ser um tipo de referência ou um tipo de valor não anulável, ocorre um erro de tempo de compilação.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.

    • Se T0 é um tipo de valor não nulo e, em seguida, o tipo de E é T0?e o significado de E é o mesmo queIf 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
      

      exceto pelo fato de P é avaliada apenas uma vez.except that P is evaluated only once.

    • Caso contrário, o tipo de E é T0 e o significado E é o mesmo queOtherwise the type of E is T0, and the meaning of E is the same as

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

      exceto pelo fato de P é avaliada apenas uma vez.except that P is evaluated only once.

Se E1 em si um null_conditional_expression, em seguida, essas regras são aplicadas novamente, os testes para de aninhamento null até que não haja nenhuma outra ?do, e a expressão foi reduzida todo o caminho para baixo a expressão de primário 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.

Por exemplo, se a expressão a.b?[0]?.c() ocorre como uma instrução de expressão, como a instrução:For example, if the expression a.b?[0]?.c() occurs as a statement-expression, as in the statement:

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

seu significado é equivalente a:its meaning is equivalent to:

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

que novamente é equivalente a:which again is equivalent to:

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

Exceto que a.b e a.b[0] são avaliadas apenas uma vez.Except that a.b and a.b[0] are evaluated only once.

Se ele ocorrer em um contexto em que seu valor é usado, como em:If it occurs in a context where its value is used, as in:

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

e supondo que o tipo da invocação do final não é um tipo de valor não anulável, seu significado é equivalente a: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();

Exceto que a.b e a.b[0] são avaliadas apenas uma vez.except that a.b and a.b[0] are evaluated only once.

Expressões de nulo-condicional como inicializadores de projeçãoNull-conditional expressions as projection initializers

Uma expressão condicional nulo é permitida somente como uma member_declarator em um anonymous_object_creation_expression (expressões de criação de objeto anônimo) se ele termina com um acesso de membro (opcionalmente nulo-condicional).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. Gramaticalmente, esse requisito pode ser expresso como: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?
    ;

Esse é um caso especial da gramática para null_conditional_expression acima.This is a special case of the grammar for null_conditional_expression above. Produção member_declarator na expressões de criação de objeto anônimo , em seguida, inclua apenas null_conditional_member_access.The production for member_declarator in Anonymous object creation expressions then includes only null_conditional_member_access.

Expressões de nulo-condicional como expressões de instruçãoNull-conditional expressions as statement expressions

Uma expressão condicional nulo é permitida somente como uma statement_expression (instruções de expressão) se ele termina com uma invocação.A null-conditional expression is only allowed as a statement_expression (Expression statements) if it ends with an invocation. Gramaticalmente, esse requisito pode ser expresso como:Grammatically, this requirement can be expressed as:

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

Esse é um caso especial da gramática para null_conditional_expression acima.This is a special case of the grammar for null_conditional_expression above. Produção statement_expression na instruções de expressão , em seguida, inclua apenas null_conditional_invocation_expression.The production for statement_expression in Expression statements then includes only null_conditional_invocation_expression.

Operador unário de adiçãoUnary plus operator

Para uma operação do formulário +x, resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicado para selecionar uma implementação do operador específico.For an operation of the form +x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. O operando será convertido ao tipo de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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. Os operadores de mais unária predefinida são: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);

Para cada um desses operadores, o resultado é simplesmente o valor do operando.For each of these operators, the result is simply the value of the operand.

Operador unário de subtraçãoUnary minus operator

Para uma operação do formulário -x, resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicado para selecionar uma implementação do operador específico.For an operation of the form -x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. O operando será convertido ao tipo de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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. Os operadores de negação predefinidos são:The predefined negation operators are:

  • Negação de inteiro:Integer negation:

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

    O resultado é calculado subtraindo x de zero.The result is computed by subtracting x from zero. Se o valor de x é o menor valor representável do tipo de operando (-2 ^ 31 para int ou -2 ^ 63 para long), em seguida, a negação matemática do x não for representável no tipo de operando.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. Se isso ocorrer dentro de um checked contexto, uma System.OverflowException gerada; se ele ocorrer dentro de um unchecked contexto, o resultado é o valor do operando, e o estouro não será relatado.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.

    Se o operando do operador de negação é do tipo uint, ele será convertido ao tipo long, e o tipo do resultado é 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. Uma exceção é a regra que permite que o int valor de -2147483648 (-2 ^ 31) a ser gravado como um literal de inteiro decimal (literais inteiros).An exception is the rule that permits the int value -2147483648 (-2^31) to be written as a decimal integer literal (Integer literals).

    Se o operando do operador de negação é do tipo ulong, ocorre um erro de tempo de compilação.If the operand of the negation operator is of type ulong, a compile-time error occurs. Uma exceção é a regra que permite que o long valor de -9223372036854775808 (-2 ^ 63) a ser gravado como um literal de inteiro decimal (literais inteiros).An exception is the rule that permits the long value -9223372036854775808 (-2^63) to be written as a decimal integer literal (Integer literals).

  • Negação de ponto flutuante:Floating-point negation:

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

    O resultado é o valor de x com o sinal invertido.The result is the value of x with its sign inverted. Se x é NaN, o resultado também é NaN.If x is NaN, the result is also NaN.

  • Negação decimal:Decimal negation:

    decimal operator -(decimal x);
    

    O resultado é calculado subtraindo x de zero.The result is computed by subtracting x from zero. Negação decimal é equivalente a usar o operador do tipo de menos unário System.Decimal.Decimal negation is equivalent to using the unary minus operator of type System.Decimal.

Operador de negação lógicoLogical negation operator

Para uma operação do formulário !x, resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicado para selecionar uma implementação do operador específico.For an operation of the form !x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. O operando será convertido ao tipo de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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. Existe apenas um operador de negação lógica predefinidos:Only one predefined logical negation operator exists:

bool operator !(bool x);

Esse operador calcula a negação lógica do operando: Se o operando true, o resultado é false.This operator computes the logical negation of the operand: If the operand is true, the result is false. Se o operando false, o resultado é true.If the operand is false, the result is true.

Operador de complemento bit a bitBitwise complement operator

Para uma operação do formulário ~x, resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicado para selecionar uma implementação do operador específico.For an operation of the form ~x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. O operando será convertido ao tipo de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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. Os operadores de complemento bit a bit predefinidos são:The predefined bitwise complement operators are:

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

Para cada um desses operadores, o resultado da operação é o complemento bit a bit de x.For each of these operators, the result of the operation is the bitwise complement of x.

Cada tipo de enumeração E implicitamente fornece o operador de complemento bit a bit a seguir:Every enumeration type E implicitly provides the following bitwise complement operator:

E operator ~(E x);

O resultado da avaliação ~x, onde x é uma expressão de um tipo de enumeração E com um tipo subjacente U, é exatamente o mesmo que avaliar (E)(~(U)x), exceto que a conversão em E é sempre é executada como se estiver em um unchecked contexto (os operadores marcados e desmarcados).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).

Operadores de incremento e decremento pré-fixadosPrefix increment and decrement operators

pre_increment_expression
    : '++' unary_expression
    ;

pre_decrement_expression
    : '--' unary_expression
    ;

O operando de um incremento de prefixo ou decremento operação deve ser uma expressão classificada como uma variável, um acesso de propriedade ou um acesso do indexador.The operand of a prefix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. O resultado da operação é um valor do mesmo tipo como o operando.The result of the operation is a value of the same type as the operand.

Se o operando de um prefixo de incrementar ou operação de decremento é uma propriedade ou o acesso do indexador, propriedade ou indexador deve ter uma get e um set acessador.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. Se isso não for o caso, ocorre um erro em tempo de vinculação.If this is not the case, a binding-time error occurs.

Resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicado para selecionar uma implementação do operador específico.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Predefinidas ++ e -- operadores existem para os seguintes tipos: sbyte, byte, short, ushort, int, uint, long, ulong, char , float, double, decimale qualquer tipo de enumeração.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Predefinido ++ operadores retornam o valor produzido pela adição de 1 para o operando e predefinido -- operadores retornam o valor produzido pela subtração de 1 de operando.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. Em um checked contexto, se o resultado dessa adição ou subtração está fora do intervalo do tipo de resultado e o tipo de resultado é um tipo integral ou um tipo de enumeração, um System.OverflowException é gerada.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.

O processamento de tempo de execução de um incremento de prefixo ou operação do formulário de decremento ++x ou --x consiste as seguintes etapas:The run-time processing of a prefix increment or decrement operation of the form ++x or --x consists of the following steps:

  • Se x é classificado como uma variável:If x is classified as a variable:
    • x é avaliado para produzir a variável.x is evaluated to produce the variable.
    • O operador selecionado é invocado com o valor de x como seu argumento.The selected operator is invoked with the value of x as its argument.
    • O valor retornado pelo operador é armazenado no local fornecido pela avaliação de x.The value returned by the operator is stored in the location given by the evaluation of x.
    • O valor retornado pelo operador torna-se o resultado da operação.The value returned by the operator becomes the result of the operation.
  • Se x é classificado como um acesso de propriedade ou indexador:If x is classified as a property or indexer access:
    • A expressão de instância (se x não é static) e a lista de argumentos (se x é um indexador de acesso) associadas com x são avaliados, e os resultados são usados em subsequente get e set invocações do acessador.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.
    • O get acessador de x é invocado.The get accessor of x is invoked.
    • O operador selecionado é invocado com o valor retornado pelo get acessador como seu argumento.The selected operator is invoked with the value returned by the get accessor as its argument.
    • O set acessador da x é invocado com o valor retornado pelo operador como seu value argumento.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • O valor retornado pelo operador torna-se o resultado da operação.The value returned by the operator becomes the result of the operation.

O ++ e -- operadores também dão suporte a pós-fixação notação (incremento de sufixo e operadores de decremento).The ++ and -- operators also support postfix notation (Postfix increment and decrement operators). Normalmente, o resultado de x++ ou x-- é o valor da x antes da operação, enquanto que o resultado da ++x ou --x é o valor do x após a operação.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. Em ambos os casos, x em si tem o mesmo valor após a operação.In either case, x itself has the same value after the operation.

Uma operator++ ou operator-- implementação pode ser invocada usando a notação de prefixo ou sufixo.An operator++ or operator-- implementation can be invoked using either postfix or prefix notation. Não é possível ter implementações de operadores separados para as duas notações.It is not possible to have separate operator implementations for the two notations.

Expressões de conversãoCast expressions

Um cast_expression é usado para converter explicitamente uma expressão para um determinado tipo.A cast_expression is used to explicitly convert an expression to a given type.

cast_expression
    : '(' type ')' unary_expression
    ;

Um cast_expression do formulário (T)E, onde T é um tipo e E é uma unary_expression, executa um explícito conversão (conversões explícitas) do valor de E digitar 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. Se nenhuma conversão explícita existe a partir E para T, ocorrerá um erro em tempo de associação.If no explicit conversion exists from E to T, a binding-time error occurs. Caso contrário, o resultado é o valor produzido pela conversão explícita.Otherwise, the result is the value produced by the explicit conversion. O resultado sempre é classificado como um valor, mesmo se E denota uma variável.The result is always classified as a value, even if E denotes a variable.

A gramática para um cast_expression leva a determinados ambiguidades sintáticas.The grammar for a cast_expression leads to certain syntactic ambiguities. Por exemplo, a expressão (x)-y pode ser interpretado como um cast_expression (uma conversão de -y digitar x) ou como um additive_expression combinado com um parenthesized_expression (que calcula o valor 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).

Para resolver cast_expression ambiguidades, a regra a seguir existir: Uma sequência de um ou mais tokens (espaço em branco) colocado entre parênteses é considerado o início de um cast_expression apenas se pelo menos um dos seguintes forem verdadeiro: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:

  • A sequência de tokens é a gramática correta para uma tipo, mas não para um expressão.The sequence of tokens is correct grammar for a type, but not for an expression.
  • A sequência de tokens é a gramática correta para uma tipo, e o token imediatamente após os parênteses de fechamento é o token "~", o token "!", o token "(", um identificador (sequências de escape de caractere Unicode), uma literal (literais), ou qualquer palavra-chave(Palavras-chave), exceto as e is.The sequence of tokens is correct grammar for a type, and the token immediately following the closing parentheses is the token "~", the token "!", the token "(", an identifier (Unicode character escape sequences), a literal (Literals), or any keyword (Keywords) except as and is.

O termo "gramática correta" acima significa apenas que a sequência de tokens deve estar de acordo com a produção gramatical específica.The term "correct grammar" above means only that the sequence of tokens must conform to the particular grammatical production. Especificamente, ele não considera o significado real de todos os identificadores constituintes.It specifically does not consider the actual meaning of any constituent identifiers. Por exemplo, se x e y são os identificadores, em seguida, x.y é a gramática correta para um tipo, mesmo se x.y , na verdade, não denota um tipo.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.

Da regra de Desambiguidade segue que, se x e y são identificadores, (x)y, (x)(y), e (x)(-y) são cast_expressions, mas (x)-y é não, mesmo se x identifica um tipo.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. No entanto, se x é uma palavra-chave que identifica um tipo predefinido (como int), em seguida, todos os quatro formulários são cast_expressions (porque tal uma palavra-chave não pode ser uma expressão, possivelmente, por si só).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).

Expressões awaitAwait expressions

O operador de espera é usado para suspender a avaliação da função assíncrona até que a operação assíncrona representada pelo operando seja concluída.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
    ;

Uma await_expression só é permitida no corpo de uma função assíncrona (iteradores).An await_expression is only allowed in the body of an async function (Iterators). Dentro do delimitador mais próximo função assíncrona, um await_expression pode não ocorrer nesses locais:Within the nearest enclosing async function, an await_expression may not occur in these places:

  • Dentro de uma função anônima do aninhada (não assíncronas)Inside a nested (non-async) anonymous function
  • Dentro do bloco de um lock_statementInside the block of a lock_statement
  • Em um contexto inseguroIn an unsafe context

Observe que um await_expression não pode ocorrer na maioria dos lugares dentro de uma query_expression, porque aquelas sintaticamente são transformadas para usar as expressões lambda não assíncronas.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.

Dentro de uma função assíncrona, await não pode ser usado como um identificador.Inside of an async function, await cannot be used as an identifier. Portanto, não há nenhuma ambiguidade sintática entre expressões await e várias expressões que envolvem identificadores.There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. Fora de funções assíncronas, await atua como um identificador normal.Outside of async functions, await acts as a normal identifier.

O operando de um await_expression é chamado de tarefa.The operand of an await_expression is called the task. Ele representa uma operação assíncrona que pode ou não pode ser concluída no momento a await_expression é avaliada.It represents an asynchronous operation that may or may not be complete at the time the await_expression is evaluated. É a finalidade do operador await suspender a execução da função assíncrona até que a tarefa aguardada seja concluída e, em seguida, obter seu resultado.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.

Expressões de awaitableAwaitable expressions

A tarefa de uma expressão await é necessária para ser aguardável.The task of an await expression is required to be awaitable. Uma expressão t é awaitable, se tiver mantido por um dos seguintes:An expression t is awaitable if one of the following holds:

  • t é do tipo de tempo de compilação dynamict is of compile time type dynamic
  • t tem um método de extensão ou de instância acessível chamado GetAwaiter sem parâmetros e nenhum parâmetro de tipo e um tipo de retorno A para o qual todos os itens a seguir manter: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 implementa a interface System.Runtime.CompilerServices.INotifyCompletion (daqui em diante, conhecido como INotifyCompletion para fins de brevidade)A implements the interface System.Runtime.CompilerServices.INotifyCompletion (hereafter known as INotifyCompletion for brevity)
    • A tem uma propriedade de instância acessível e legível IsCompleted do tipo boolA has an accessible, readable instance property IsCompleted of type bool
    • A tem um método de instância acessível GetResult sem parâmetros e nenhum parâmetro de tipoA has an accessible instance method GetResult with no parameters and no type parameters

A finalidade de GetAwaiter método é obter uma awaiter para a tarefa.The purpose of the GetAwaiter method is to obtain an awaiter for the task. O tipo A é chamado de tipo awaiter para a expressão await.The type A is called the awaiter type for the await expression.

A finalidade de IsCompleted é de propriedade determinar se a tarefa já foi concluída.The purpose of the IsCompleted property is to determine if the task is already complete. Nesse caso, não é necessário para suspender a avaliação.If so, there is no need to suspend evaluation.

A finalidade do INotifyCompletion.OnCompleted método é inscrever-se de "continuação" para a tarefa; ou seja, um delegado (do tipo System.Action) que será invocado quando a tarefa for concluída.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.

A finalidade de GetResult método é obter o resultado da tarefa quando ela for concluída.The purpose of the GetResult method is to obtain the outcome of the task once it is complete. Esse resultado pode ser a conclusão bem-sucedida, possivelmente com um valor de resultado, ou pode ser uma exceção que é lançada pelo GetResult método.This outcome may be successful completion, possibly with a result value, or it may be an exception which is thrown by the GetResult method.

Expressões de classificação de awaitClassification of await expressions

A expressão await t é classificado da mesma forma que a expressão (t).GetAwaiter().GetResult().The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Portanto, se o tipo de retorno de GetResult está void, o await_expression é classificado como nada.Thus, if the return type of GetResult is void, the await_expression is classified as nothing. Se ele tiver um tipo de retorno não nulo T, o await_expression é classificado como um valor do tipo T.If it has a non-void return type T, the await_expression is classified as a value of type T.

Expressões de avaliação do tempo de execução do awaitRuntime evaluation of await expressions

Em tempo de execução, a expressão await t é avaliada como segue:At runtime, the expression await t is evaluated as follows:

  • Um awaiter a é obtido avaliando a expressão (t).GetAwaiter().An awaiter a is obtained by evaluating the expression (t).GetAwaiter().
  • Um bool b é obtido avaliando a expressão (a).IsCompleted.A bool b is obtained by evaluating the expression (a).IsCompleted.
  • Se b está false e em seguida, avaliação depende a implementa a interface System.Runtime.CompilerServices.ICriticalNotifyCompletion (daqui em diante, conhecido como ICriticalNotifyCompletion para fins de brevidade).If b is false then evaluation depends on whether a implements the interface System.Runtime.CompilerServices.ICriticalNotifyCompletion (hereafter known as ICriticalNotifyCompletion for brevity). Essa verificação é feita no tempo; de ligação ou seja, em tempo de execução se a tem o tipo de tempo de compilação dynamice em tempo de compilação caso contrário.This check is done at binding time; i.e. at runtime if a has the compile time type dynamic, and at compile time otherwise. Deixe r denotam o delegado de continuação (iteradores):Let r denote the resumption delegate (Iterators):
    • Se a não implementa ICriticalNotifyCompletion, em seguida, a expressão (a as (INotifyCompletion)).OnCompleted(r) é avaliada.If a does not implement ICriticalNotifyCompletion, then the expression (a as (INotifyCompletion)).OnCompleted(r) is evaluated.
    • Se a implementar ICriticalNotifyCompletion, em seguida, a expressão (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) é avaliada.If a does implement ICriticalNotifyCompletion, then the expression (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) is evaluated.
    • Avaliação, em seguida, é suspenso e controle é retornado ao chamador da função assíncrona atual.Evaluation is then suspended, and control is returned to the current caller of the async function.
  • Qualquer um dos imediatamente após (se b foi true), ou mediante posterior invocação de delegado de continuação (se b foi false), a expressão (a).GetResult() é avaliada.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. Se ela retorna um valor, esse valor é o resultado do await_expression.If it returns a value, that value is the result of the await_expression. Caso contrário, o resultado é que nada.Otherwise the result is nothing.

A implementação de um awaiter métodos da interface INotifyCompletion.OnCompleted e ICriticalNotifyCompletion.UnsafeOnCompleted deve fazer com que o delegado r a ser invocado no máximo uma vez.An awaiter's implementation of the interface methods INotifyCompletion.OnCompleted and ICriticalNotifyCompletion.UnsafeOnCompleted should cause the delegate r to be invoked at most once. Caso contrário, o comportamento da função async será indefinido.Otherwise, the behavior of the enclosing async function is undefined.

Operadores aritméticosArithmetic operators

O *, /, %, +, e - operadores são chamados de operadores aritméticos.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
    ;

Se um operando do operador aritmético tem o tipo de tempo de compilação dynamic, em seguida, a expressão está associada dinamicamente (vinculação dinâmica).If an operand of an arithmetic operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Nesse caso é o tipo de tempo de compilação da expressão dynamic, e a resolução descrita a seguir ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que tenham o tipo de tempo de compilação 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.

Operador de multiplicaçãoMultiplication operator

Para uma operação do formulário x * y, resolução de sobrecarga de operador binário (resolução de sobrecarga de operador binário) é aplicado para selecionar uma implementação do operador específico.For an operation of the form x * y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Os operandos são convertidos nos tipos de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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.

Os operadores de multiplicação predefinidos estão listados abaixo.The predefined multiplication operators are listed below. Todos os operadores compute o produto dos x e y.The operators all compute the product of x and y.

  • Multiplicação de inteiro: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);
    

    Em um checked contexto, se o produto está fora do intervalo do tipo de resultado, um System.OverflowException é gerada.In a checked context, if the product is outside the range of the result type, a System.OverflowException is thrown. Em um unchecked contexto, estouros não são relatados e quaisquer bits de ordem superior significativos fora do intervalo do tipo de resultado são descartados.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Multiplicação de ponto flutuante:Floating-point multiplication:

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

    O produto é calculado de acordo com as regras de aritmética do IEEE 754.The product is computed according to the rules of IEEE 754 arithmetic. A tabela a seguir lista os resultados de todas as combinações possíveis de valores Finitas diferente de zero, zeros, infinitos e do NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Na tabela, x e y são valores positivos de finitos.In the table, x and y are positive finite values. z é o resultado de x * y.z is the result of x * y. Se o resultado for muito grande para o tipo de destino, z é infinito.If the result is too large for the destination type, z is infinity. Se o resultado for muito pequeno para o tipo de destino, z é zero.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
  • Multiplicação decimal:Decimal multiplication:

    decimal operator *(decimal x, decimal y);
    

    Se o valor resultante é muito grande para representar o decimal formato, um System.OverflowException é gerada.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Se o valor do resultado for muito pequeno para representar o decimal formato, o resultado é zero.If the result value is too small to represent in the decimal format, the result is zero. A escala do resultado, antes de qualquer arredondamento, é a soma das escalas dos dois operandos.The scale of the result, before any rounding, is the sum of the scales of the two operands.

    Multiplicação decimal é equivalente a usar o operador de multiplicação do tipo System.Decimal.Decimal multiplication is equivalent to using the multiplication operator of type System.Decimal.

Operador de divisãoDivision operator

Para uma operação do formulário x / y, resolução de sobrecarga de operador binário (resolução de sobrecarga de operador binário) é aplicado para selecionar uma implementação do operador específico.For an operation of the form x / y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Os operandos são convertidos nos tipos de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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.

Os operadores de divisão predefinidos estão listados abaixo.The predefined division operators are listed below. O quociente de computação de todos os operadores x e y.The operators all compute the quotient of x and y.

  • Divisão de inteiros: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);
    

    Se o valor do operando à direita for zero, um System.DivideByZeroException é gerada.If the value of the right operand is zero, a System.DivideByZeroException is thrown.

    A divisão Arredonda o resultado em direção a zero.The division rounds the result towards zero. Assim, o valor absoluto do resultado é o maior inteiro possível que seja menor ou igual ao valor absoluto do quociente de dois operandos.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. O resultado é zero ou positivo quando os dois operandos têm o mesmo sinal e zero ou negativo quando os dois operandos tiverem oposta sinais.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.

    Se o operando esquerdo for menor representável int ou long valor e o operando direito é -1, ocorre um estouro.If the left operand is the smallest representable int or long value and the right operand is -1, an overflow occurs. Em um checked contexto, isso faz com que um System.ArithmeticException (ou uma subclasse disso) seja lançada.In a checked context, this causes a System.ArithmeticException (or a subclass thereof) to be thrown. Em um unchecked contexto, ele é definido pela implementação sobre se um System.ArithmeticException (ou uma subclasse disso) é gerada ou o estouro é relatado com o valor resultante, sendo que a do operando à esquerda.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.

  • Divisão de ponto flutuante:Floating-point division:

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

    O quociente é calculado de acordo com as regras de aritmética do IEEE 754.The quotient is computed according to the rules of IEEE 754 arithmetic. A tabela a seguir lista os resultados de todas as combinações possíveis de valores Finitas diferente de zero, zeros, infinitos e do NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Na tabela, x e y são valores positivos de finitos.In the table, x and y are positive finite values. z é o resultado de x / y.z is the result of x / y. Se o resultado for muito grande para o tipo de destino, z é infinito.If the result is too large for the destination type, z is infinity. Se o resultado for muito pequeno para o tipo de destino, z é zero.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
  • Divisão decimal:Decimal division:

    decimal operator /(decimal x, decimal y);
    

    Se o valor do operando à direita for zero, um System.DivideByZeroException é gerada.If the value of the right operand is zero, a System.DivideByZeroException is thrown. Se o valor resultante é muito grande para representar o decimal formato, um System.OverflowException é gerada.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Se o valor do resultado for muito pequeno para representar o decimal formato, o resultado é zero.If the result value is too small to represent in the decimal format, the result is zero. A escala do resultado é a escala menor que irá preservar um resultado igual ao valor decimal representável para o resultado matemático true mais próximo.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.

    Divisão decimal é equivalente a usar o operador de divisão do tipo System.Decimal.Decimal division is equivalent to using the division operator of type System.Decimal.

Operador de restoRemainder operator

Para uma operação do formulário x % y, resolução de sobrecarga de operador binário (resolução de sobrecarga de operador binário) é aplicado para selecionar uma implementação do operador específico.For an operation of the form x % y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Os operandos são convertidos nos tipos de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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.

Os operadores de restante predefinidos estão listados abaixo.The predefined remainder operators are listed below. Todos os operadores compute o resto da divisão entre x e y.The operators all compute the remainder of the division between x and y.

  • Resto inteiro: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);
    

    O resultado de x % y é o valor produzido por x - (x / y) * y.The result of x % y is the value produced by x - (x / y) * y. Se y for zero, um System.DivideByZeroException é gerada.If y is zero, a System.DivideByZeroException is thrown.

    Se o operando esquerdo for menor int ou long é de valor e o operando direito -1, um System.OverflowException é gerada.If the left operand is the smallest int or long value and the right operand is -1, a System.OverflowException is thrown. Em nenhum caso faz x % y lançar uma exceção onde x / y não geraria uma exceção.In no case does x % y throw an exception where x / y would not throw an exception.

  • Ponto flutuante restante:Floating-point remainder:

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

    A tabela a seguir lista os resultados de todas as combinações possíveis de valores Finitas diferente de zero, zeros, infinitos e do NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Na tabela, x e y são valores positivos de finitos.In the table, x and y are positive finite values. z é o resultado de x % y e é computado como x - n * y, onde n é o maior inteiro possíveis que é menor que ou igual a 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. Esse método de computação o restante é análogo àquela utilizada para operandos de inteiro, mas é diferente da definição de IEEE 754 (no qual n é o inteiro mais próximo ao 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
  • Decimal restante:Decimal remainder:

    decimal operator %(decimal x, decimal y);
    

    Se o valor do operando à direita for zero, um System.DivideByZeroException é gerada.If the value of the right operand is zero, a System.DivideByZeroException is thrown. A escala do resultado, antes de qualquer arredondamento, é o maior entre as escalas de dois operandos, e o sinal do resultado, se diferente de zero, é o mesmo da 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.

    Decimal restante é equivalente a usar o operador de resto do tipo System.Decimal.Decimal remainder is equivalent to using the remainder operator of type System.Decimal.

Operador de adiçãoAddition operator

Para uma operação do formulário x + y, resolução de sobrecarga de operador binário (resolução de sobrecarga de operador binário) é aplicado para selecionar uma implementação do operador específico.For an operation of the form x + y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Os operandos são convertidos nos tipos de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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.

Os operadores de adição predefinidas são listados abaixo.The predefined addition operators are listed below. Para tipos numéricos e de enumeração, os operadores de adição predefinidos calcular a soma dos dois operandos.For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. Quando um ou ambos os operandos são do tipo cadeia de caracteres, os operadores de adição predefinidos concatenar a representação de cadeia de caracteres dos operandos.When one or both operands are of type string, the predefined addition operators concatenate the string representation of the operands.

  • Adição de inteiro: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);
    

    Em um checked contexto, se a soma está fora do intervalo do tipo de resultado, um System.OverflowException é gerada.In a checked context, if the sum is outside the range of the result type, a System.OverflowException is thrown. Em um unchecked contexto, estouros não são relatados e quaisquer bits de ordem superior significativos fora do intervalo do tipo de resultado são descartados.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Adição de ponto flutuante:Floating-point addition:

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

    A soma é calculada de acordo com as regras de aritmética do IEEE 754.The sum is computed according to the rules of IEEE 754 arithmetic. A tabela a seguir lista os resultados de todas as combinações possíveis de valores Finitas diferente de zero, zeros, infinitos e do NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Na tabela, x e y são valores Finitas diferente de zero, e z é o resultado de x + y.In the table, x and y are nonzero finite values, and z is the result of x + y. Se x e y têm a mesma magnitude mas oposta sinais, z for zero positivo.If x and y have the same magnitude but opposite signs, z is positive zero. Se x + y é muito grande para ser representado no tipo de destino, z é infinito com o mesmo sinal 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.

    yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    xx zz xx xx +inf+inf -inf-inf NaNNaN
    +0+0 yy +0+0 +0+0 +inf+inf -inf-inf NaNNaN
    -0-0 yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    +inf+inf +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN NaNNaN
    -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN -inf-inf NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Adição de decimal:Decimal addition:

    decimal operator +(decimal x, decimal y);
    

    Se o valor resultante é muito grande para representar o decimal formato, um System.OverflowException é gerada.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. A escala do resultado, antes de qualquer arredondamento, é o maior entre as escalas de dois operandos.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    Adição de decimal é equivalente a usar o operador de adição do tipo System.Decimal.Decimal addition is equivalent to using the addition operator of type System.Decimal.

  • Adição de enumeração.Enumeration addition. Implicitamente, a cada tipo de enumeração fornece o seguinte predefinidas operadores, onde E é o tipo de enumeração, e U é o tipo subjacente 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);
    

    Em tempo de execução, esses operadores são avaliados exatamente como (E)((U)x + (U)y).At run-time these operators are evaluated exactly as (E)((U)x + (U)y).

  • Concatenação de cadeia de caracteres:String concatenation:

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

    Essas sobrecargas do binário + operador realizam a concatenação de cadeia de caracteres.These overloads of the binary + operator perform string concatenation. Se um operando de concatenação de cadeia de caracteres é null, uma cadeia de caracteres vazia é substituída.If an operand of string concatenation is null, an empty string is substituted. Caso contrário, qualquer argumento de cadeia de caracteres não é convertido em sua representação de cadeia de caracteres com a invocação virtual ToString método herdado do tipo object.Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. Se ToString retorna null, uma cadeia de caracteres vazia é substituída.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
        }
    }
    

    O resultado do operador de concatenação de cadeia de caracteres é uma cadeia de caracteres que consiste em caracteres do operando à esquerda seguido pelos caracteres do operando à direita. O operador de concatenação de cadeia de caracteres nunca retorna um null valor. Um System.OutOfMemoryException poderá ser gerada se não há memória suficiente disponível para alocar a cadeia de caracteres resultante.A System.OutOfMemoryException may be thrown if there is not enough memory available to allocate the resulting string.

  • Combinação de delegado.Delegate combination. Cada tipo de delegado implicitamente fornece o operador pré-definido seguinte, onde D é o tipo de delegado:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator +(D x, D y);
    

    O binário + operador executa a combinação de delegados quando ambos os operandos são de algum tipo de delegado D.The binary + operator performs delegate combination when both operands are of some delegate type D. (Se os operandos tiverem tipos diferentes de delegado, ocorrerá um erro em tempo de associação.) Se for o primeiro operando null, o resultado da operação é o valor do segundo operando (mesmo que seja também 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). Caso contrário, se o segundo operando for null, o resultado da operação será o valor do primeiro operando.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. Caso contrário, o resultado da operação é uma nova instância delegada que, quando invocado, invoca o primeiro operando e, em seguida, invoca o segundo operando.Otherwise, the result of the operation is a new delegate instance that, when invoked, invokes the first operand and then invokes the second operand. Para obter exemplos de combinação de delegados, consulte operador de subtração e invocação de delegado.For examples of delegate combination, see Subtraction operator and Delegate invocation. Uma vez que System.Delegate não é um tipo de delegado operator  + não está definido para ele.Since System.Delegate is not a delegate type, operator + is not defined for it.

Operador de subtraçãoSubtraction operator

Para uma operação do formulário x - y, resolução de sobrecarga de operador binário (resolução de sobrecarga de operador binário) é aplicado para selecionar uma implementação do operador específico.For an operation of the form x - y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Os operandos são convertidos nos tipos de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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.

Os operadores de subtração predefinidas são listados abaixo.The predefined subtraction operators are listed below. Os operadores todos subtrair y de x.The operators all subtract y from x.

  • Subtração de inteiro: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);
    

    Em um checked contexto, se a diferença está fora do intervalo do tipo de resultado, um System.OverflowException é gerada.In a checked context, if the difference is outside the range of the result type, a System.OverflowException is thrown. Em um unchecked contexto, estouros não são relatados e quaisquer bits de ordem superior significativos fora do intervalo do tipo de resultado são descartados.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Subtração de ponto flutuante:Floating-point subtraction:

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

    A diferença é calculada de acordo com as regras de aritmética do IEEE 754.The difference is computed according to the rules of IEEE 754 arithmetic. A tabela a seguir lista os resultados de todas as combinações possíveis de valores Finitas diferente de zero, zeros, infinitos e NaNs.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaNs. Na tabela, x e y são valores Finitas diferente de zero, e z é o resultado de x - y.In the table, x and y are nonzero finite values, and z is the result of x - y. Se x e y forem iguais, z for zero positivo.If x and y are equal, z is positive zero. Se x - y é muito grande para ser representado no tipo de destino, z é infinito com o mesmo sinal 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.

    yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    xx zz xx xx -inf-inf +inf+inf NaNNaN
    +0+0 -y-y +0+0 +0+0 -inf-inf +inf+inf NaNNaN
    -0-0 -y-y -0-0 +0+0 -inf-inf +inf+inf NaNNaN
    +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN +inf+inf NaNNaN
    -inf-inf -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN NaNNaN
    NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN
  • Subtração decimal:Decimal subtraction:

    decimal operator -(decimal x, decimal y);
    

    Se o valor resultante é muito grande para representar o decimal formato, um System.OverflowException é gerada.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. A escala do resultado, antes de qualquer arredondamento, é o maior entre as escalas de dois operandos.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    Subtração de decimal é equivalente a usar o operador de subtração do tipo System.Decimal.Decimal subtraction is equivalent to using the subtraction operator of type System.Decimal.

  • Subtração de enumeração.Enumeration subtraction. Cada tipo de enumeração implicitamente fornece o operador pré-definido seguinte, onde E é o tipo de enumeração, e U é o tipo subjacente 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);
    

    Esse operador é avaliado exatamente como (U)((U)x - (U)y).This operator is evaluated exactly as (U)((U)x - (U)y). Em outras palavras, o operador calcula a diferença entre os valores ordinais das x e y, e o tipo do resultado é o tipo subjacente da enumeração.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);
    

    Esse operador é avaliado exatamente como (E)((U)x - y).This operator is evaluated exactly as (E)((U)x - y). Em outras palavras, o operador subtrai um valor do tipo subjacente da enumeração, que rende um valor da enumeração.In other words, the operator subtracts a value from the underlying type of the enumeration, yielding a value of the enumeration.

  • Remoção de delegado.Delegate removal. Cada tipo de delegado implicitamente fornece o operador pré-definido seguinte, onde D é o tipo de delegado:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator -(D x, D y);
    

    O binário - operador executa a remoção de delegado quando ambos os operandos são de algum tipo de delegado D.The binary - operator performs delegate removal when both operands are of some delegate type D. Se os operandos tiverem tipos diferentes de delegado, ocorrerá um erro de tempo de associação.If the operands have different delegate types, a binding-time error occurs. Se for o primeiro operando null, o resultado da operação é null.If the first operand is null, the result of the operation is null. Caso contrário, se o segundo operando for null, o resultado da operação será o valor do primeiro operando.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. Caso contrário, ambos os operandos representam listas de invocação (declarações de delegado) ter uma ou mais entradas e o resultado é uma nova lista de invocação, consistindo de lista do primeiro operando com entradas do segundo operando removidas do forneceu a lista do segundo operando é uma sublista contígua adequada do primeiro.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. (Para determinar igualdade sublista, as entradas correspondentes são comparadas como para o operador de igualdade de delegado (delegar operadores de igualdade).) Caso contrário, o resultado é o valor do operando à esquerda.(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. Nenhuma das listas dos operandos é alterada no processo.Neither of the operands' lists is changed in the process. Se a lista do segundo operando corresponder a várias sublistas contíguos entradas da lista do primeiro operando, a sublista de correspondência mais à direita das entradas contíguas é removida.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. Se os resultados da remoção em uma lista vazia, o resultado será null.If removal results in an empty list, the result is null. Por exemplo: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
        }
    }
    

Operadores shiftShift operators

O << e >> operadores são usados para executar operações de mudança 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
    ;

Se um operando de um shift_expression tem o tipo de tempo de compilação dynamic, em seguida, a expressão está associada dinamicamente (vinculação dinâmica).If an operand of a shift_expression has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Nesse caso é o tipo de tempo de compilação da expressão dynamic, e a resolução descrita a seguir ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que tenham o tipo de tempo de compilação 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.

Para uma operação do formulário x << count ou x >> count, resolução de sobrecarga de operador binário (resolução de sobrecarga de operador binário) é aplicado para selecionar uma implementação do operador específico.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. Os operandos são convertidos nos tipos de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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.

Ao declarar um operador de deslocamento sobrecarregado, o tipo do primeiro operando sempre deve ser a classe ou struct que contém a declaração do operador e o tipo do segundo operando deve ser sempre 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.

Os operadores shift predefinidas são listados abaixo.The predefined shift operators are listed below.

  • Usar SHIFT-left: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);
    

    O << turnos de operador x à esquerda por um número de bits calculado conforme descrito abaixo.The << operator shifts x left by a number of bits computed as described below.

    Os bits de ordem superior fora do intervalo do tipo de resultado x são descartados, os bits restantes são deslocados para a esquerda e as posições de bits vazios de ordem inferior são definidas como zero.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.

  • SHIFT direito: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);
    

    O >> turnos de operador x à direita por um número de bits calculado conforme descrito abaixo.The >> operator shifts x right by a number of bits computed as described below.

    Quando x é do tipo int ou long, os bits de ordem inferior do x são descartados, os bits restantes são deslocados para a direita, e as posições de bits vazios de ordem superior são definidas como zero se x é não negativo e será definida para um, se x é negativo.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.

    Quando x é do tipo uint ou ulong, os bits de ordem inferior de x são descartados, os bits restantes são deslocados para a direita, e as posições de bits vazios de ordem superior são definidas como zero.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.

Para os operadores predefinidos, o número de bits a deslocar é calculado da seguinte maneira:For the predefined operators, the number of bits to shift is computed as follows:

  • Quando o tipo de x está int ou uint, a contagem de shift é determinada pelos cinco bits inferiores de count.When the type of x is int or uint, the shift count is given by the low-order five bits of count. Em outras palavras, a contagem de deslocamento é computada a partir count & 0x1F.In other words, the shift count is computed from count & 0x1F.
  • Quando o tipo de x está long ou ulong, a contagem de deslocamento será determinada pelos seis bits inferiores de count.When the type of x is long or ulong, the shift count is given by the low-order six bits of count. Em outras palavras, a contagem de deslocamento é computada a partir count & 0x3F.In other words, the shift count is computed from count & 0x3F.

Se a contagem de deslocamento resultante for zero, os operadores shift simplesmente retornam o valor de x.If the resulting shift count is zero, the shift operators simply return the value of x.

Operações de deslocamento nunca causam estouros e produzem os mesmos resultados no checked e unchecked contextos.Shift operations never cause overflows and produce the same results in checked and unchecked contexts.

Quando o operando da esquerda a >> operador é de um tipo integral com sinal, o operador executa um deslocamento aritmético à direita no qual o valor do bit mais significativo (o bit de sinal) do operando é propagado para as posições de bit de ordem superior vazio.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. Quando o operando da esquerda a >> operador é de um tipo integral sem sinal, o operador executa um deslocamento lógico à direita no qual as posições de bit de ordem superior vazias são sempre definidas como zero.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. Para executar a operação oposta do que é inferido do tipo de operando, conversões explícitas podem ser usados.To perform the opposite operation of that inferred from the operand type, explicit casts can be used. Por exemplo, se x é uma variável do tipo int, a operação unchecked((int)((uint)x >> y)) executa um deslocamento lógico à direita do 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.

Operadores de teste de tipo e relacionalRelational and type-testing operators

O ==, !=, <, >, <=, >=, is e as operadores são chamados de operadores relacionais e de teste de tipo.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
    ;

O is operador é descrito em a é o operador e o as operador é descrito na o operador.The is operator is described in The is operator and the as operator is described in The as operator.

O ==, !=, <, >, <= e >= operadores são operadores de comparação.The ==, !=, <, >, <= and >= operators are comparison operators.

Se um operando do operador de comparação tem o tipo de tempo de compilação dynamic, em seguida, a expressão está associada dinamicamente (vinculação dinâmica).If an operand of a comparison operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Nesse caso é o tipo de tempo de compilação da expressão dynamic, e a resolução descrita a seguir ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que tenham o tipo de tempo de compilação 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.

Para uma operação do formulário x op y, onde op é um operador de comparação, a resolução de sobrecarga (deresoluçãodesobrecargadeoperadorbinário) é aplicado para selecionar uma implementação do operador específico.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. Os operandos são convertidos nos tipos de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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.

Os operadores de comparação predefinidos são descritos nas seções a seguir.The predefined comparison operators are described in the following sections. Todos os operadores de comparação predefinido retornam um resultado do tipo bool, conforme descrito na tabela a seguir.All predefined comparison operators return a result of type bool, as described in the following table.

operaçãoOperation ResultResult
x == y true Se x é igual a y, false caso contrário,true if x is equal to y, false otherwise
x != y true Se x não é igual a y, false caso contrário,true if x is not equal to y, false otherwise
x < y true Se x é menor que y, false caso contrário,true if x is less than y, false otherwise
x > y true Se x é maior que y, false caso contrário,true if x is greater than y, false otherwise
x <= y true Se x é menor que ou igual a y, false caso contrário,true if x is less than or equal to y, false otherwise
x >= y true Se x é maior que ou igual a y, false caso contrário,true if x is greater than or equal to y, false otherwise

Operadores de comparação de inteiroInteger comparison operators

Os operadores de comparação de inteiro predefinidos são: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);

Cada um desses operadores compara os valores numéricos dos operandos dois inteiros e retorna um bool valor que indica se a relação específica 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.

Operadores de comparação de ponto flutuanteFloating-point comparison operators

Os operadores de comparação de ponto flutuante predefinidos são: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);

Os operadores comparam os operandos de acordo com as regras do padrão IEEE 754:The operators compare the operands according to the rules of the IEEE 754 standard:

  • Se qualquer operando for NaN, o resultado será false para todos os operadores exceto !=, para que o resultado é true.If either operand is NaN, the result is false for all operators except !=, for which the result is true. Para qualquer dois operandos, x != y sempre produz o mesmo resultado que !(x == y).For any two operands, x != y always produces the same result as !(x == y). No entanto, quando um ou ambos os operandos são NaN, a <, >, <=, e >= operadores não produzem os mesmos resultados que a negação lógica do operador oposto.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. Por exemplo, se qualquer uma de x e y for NaN, em seguida, x < y é false, mas !(x >= y) é true.For example, if either of x and y is NaN, then x < y is false, but !(x >= y) is true.

  • Quando nenhum dos operandos for NaN, os operadores comparam os valores dos dois operandos de ponto flutuantes em relação a ordenaçãoWhen 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
    

    em que min e max são os menores e maiores finitos valores positivos que podem ser representados no formato de ponto flutuante fornecido.where min and max are the smallest and largest positive finite values that can be represented in the given floating-point format. Efeitos notáveis essa ordenação são:Notable effects of this ordering are:

    • Zeros positivos e negativos são considerados iguais.Negative and positive zeros are considered equal.
    • Um número infinito negativo é considerado menor do que todos os outros valores, mas igual a outro infinito negativo.A negative infinity is considered less than all other values, but equal to another negative infinity.
    • Um número infinito positivo é considerado maior do que todos os outros valores, mas igual ao outro infinito positivo.A positive infinity is considered greater than all other values, but equal to another positive infinity.

Operadores de comparação decimalDecimal comparison operators

Os operadores de comparação de decimal predefinidos são: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);

Cada um desses operadores compara os valores numéricos dos dois operandos de decimais e retorna um bool valor que indica se a relação específica 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. Cada comparação decimal é equivalente a usar o operador de igualdade do tipo ou correspondente relacional System.Decimal.Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal.

Operadores de igualdade boolianaBoolean equality operators

Os operadores de igualdade booliana predefinidos são:The predefined boolean equality operators are:

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

O resultado de == está true se ambos x e y são true ou se ambos os x e y são false.The result of == is true if both x and y are true or if both x and y are false. Caso contrário, o resultado será false.Otherwise, the result is false.

O resultado de != está false se ambos x e y são true ou se ambos os x e y são false.The result of != is false if both x and y are true or if both x and y are false. Caso contrário, o resultado será true.Otherwise, the result is true. Quando os operandos forem do tipo bool, o != operador produz o mesmo resultado que o ^ operador.When the operands are of type bool, the != operator produces the same result as the ^ operator.

Operadores de comparação de enumeraçãoEnumeration comparison operators

Cada tipo de enumeração implicitamente fornece os seguintes operadores de comparação predefinidos: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);

O resultado da avaliação x op y, onde x e y são expressões de um tipo de enumeração E com um tipo subjacente U, e op é um dos operadores de comparação, é exatamente o mesmo que Avaliando ((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). Em outras palavras, os operadores de comparação de tipo de enumeração simplesmente comparam os valores integrais subjacentes dos dois operandos.In other words, the enumeration type comparison operators simply compare the underlying integral values of the two operands.

Operadores de igualdade de tipo de referênciaReference type equality operators

Os operadores de igualdade do tipo de referência predefinidos são:The predefined reference type equality operators are:

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

Os operadores retornam o resultado de comparar as duas referências para igualdade ou não igualdade.The operators return the result of comparing the two references for equality or non-equality.

Uma vez que os operadores de igualdade do tipo de referência predefinidos aceitam operandos do tipo object, eles se aplicam a todos os tipos que não declaram aplicáveis operator == e operator != membros.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. Por outro lado, qualquer operadores de igualdade aplicável definidos pelo usuário efetivamente ocultam os operadores de igualdade do tipo de referência predefinidos.Conversely, any applicable user-defined equality operators effectively hide the predefined reference type equality operators.

Os operadores de igualdade do tipo de referência predefinidos exigem um destes procedimentos:The predefined reference type equality operators require one of the following:

  • Ambos os operandos forem um valor de um tipo conhecido por ser um reference_type ou o literal null.Both operands are a value of a type known to be a reference_type or the literal null. Além disso, uma conversão de referência explícita (conversões de referência explícita) existe do tipo de ambos os operandos para o tipo de outro operando.Furthermore, an explicit reference conversion (Explicit reference conversions) exists from the type of either operand to the type of the other operand.
  • Um operando for um valor do tipo T onde T é um type_parameter e o outro operando é o literal null.One operand is a value of type T where T is a type_parameter and the other operand is the literal null. Além disso T não tem a restrição de tipo de valor.Furthermore T does not have the value type constraint.

A menos que uma das seguintes condições forem verdadeiras, ocorrerá um erro de tempo de associação.Unless one of these conditions are true, a binding-time error occurs. Implicações importantes dessas regras são:Notable implications of these rules are:

  • Ele é um erro de tempo de associação a usar os operadores de igualdade do tipo de referência predefinidos para comparar duas referências que são conhecidas por ser diferente em tempo de associação.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. Por exemplo, se os tipos de tempo de associação de operandos são dois tipos de classe A e Be caso nem A nem B deriva a outra, em seguida, seria impossível para os dois operandos referenciar o mesmo objeto.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. Portanto, a operação é considerada um erro de tempo de associação.Thus, the operation is considered a binding-time error.
  • Os operadores de igualdade do tipo de referência predefinidos não permitem valor operandos do tipo a ser comparado.The predefined reference type equality operators do not permit value type operands to be compared. Portanto, a menos que um tipo de struct declara seus próprios operadores de igualdade, não é possível comparar os valores desse tipo de struct.Therefore, unless a struct type declares its own equality operators, it is not possible to compare values of that struct type.
  • Os operadores de igualdade do tipo de referência predefinidos nunca causam operações de conversão boxing ocorra para seus operandos.The predefined reference type equality operators never cause boxing operations to occur for their operands. Ele não teria sentido executar essas operações de conversão boxing, já que as referências às instâncias recém-alocada demarcadas necessariamente seriam diferente de todas as outras referências.It would be meaningless to perform such boxing operations, since references to the newly allocated boxed instances would necessarily differ from all other references.
  • Se um operando de um tipo de parâmetro de tipo T é comparado ao nulle o tipo de tempo de execução do T é um tipo de valor, o resultado da comparação é 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.

O exemplo a seguir verifica se um argumento de um tipo de parâmetro de tipo sem restrição é 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();
        ...
    }
}

O x == null constructo é permitido, embora T pode representar um tipo de valor e o resultado é simplesmente definido para ser false quando T é um tipo de valor.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.

Para uma operação do formulário x == y ou x != y, se qualquer aplicável operator == ou operator != existir, a resolução de sobrecarga de operador (resolução de sobrecarga de operador binário) selecionará as regras que operador em vez do operador de igualdade de tipo de referência predefinidos.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. No entanto, sempre é possível selecionar o operador de igualdade do tipo de referência predefinidos convertendo explicitamente um ou ambos os operandos para o tipo 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. O exemploThe 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);
    }
}

produz a saídaproduces the output

True
False
False
False

O s e t variáveis se referirem a dois diferentes string instâncias que contém os mesmos caracteres.The s and t variables refer to two distinct string instances containing the same characters. A primeira comparação gera True porque o operador de igualdade de cadeia de caracteres predefinida (operadores de igualdade de cadeia de caracteres) é selecionado quando ambos os operandos forem do tipo string.The first comparison outputs True because the predefined string equality operator (String equality operators) is selected when both operands are of type string. Todas as comparações restantes de saída False porque o operador de igualdade do tipo de referência predefinidos é selecionado quando um ou ambos os operandos forem do tipo 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.

Observe que a técnica acima não é significativa para tipos de valor.Note that the above technique is not meaningful for value types. O exemploThe example

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

gera False porque as conversões criem referências para duas instâncias separadas do box int valores.outputs False because the casts create references to two separate instances of boxed int values.

Operadores de igualdade de cadeia de caracteresString equality operators

Os operadores de igualdade de cadeia de caracteres predefinidas são:The predefined string equality operators are:

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

Dois string valores são considerados iguais quando uma das seguintes opções for verdadeira:Two string values are considered equal when one of the following is true:

  • Os dois valores forem null.Both values are null.
  • Ambos os valores são nulos referências às instâncias de cadeia de caracteres que têm caracteres idênticos e comprimentos idênticos em cada posição do caractere.Both values are non-null references to string instances that have identical lengths and identical characters in each character position.

Os operadores de igualdade de cadeia de caracteres comparam valores de cadeia de caracteres em vez de referências de cadeia de caracteres.The string equality operators compare string values rather than string references. Quando duas instâncias de cadeia de caracteres separada contêm a mesma sequência exata de caracteres, os valores das cadeias de caracteres são iguais, mas as referências são diferentes.When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. Conforme descrito em operadores de igualdade de tipo de referência, os operadores de igualdade do tipo de referência podem ser usados para comparar as referências de cadeia de caracteres em vez de valores de cadeia de caracteres.As described in Reference type equality operators, the reference type equality operators can be used to compare string references instead of string values.

Operadores de igualdade de delegadoDelegate equality operators

Cada tipo de delegado implicitamente fornece os seguintes operadores de comparação predefinidos: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);

Delegado duas instâncias são consideradas iguais da seguinte maneira:Two delegate instances are considered equal as follows:

  • Se qualquer uma das instâncias de delegado for null, eles são iguais se e somente se ambos forem null.If either of the delegate instances is null, they are equal if and only if both are null.
  • Se os delegados tem um tipo diferente de tempo de execução, eles nunca são iguais.If the delegates have different run-time type they are never equal.
  • Se ambas as instâncias de delegado têm uma lista de invocação (declarações de delegado), essas instâncias são iguais se e somente se suas listas de invocação têm o mesmo comprimento, e cada entrada na lista de invocação de um é igual a (conforme definido abaixo) para a entrada correspondente, em ordem, na lista de invocação do outro.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.

As seguintes regras regem a igualdade de entradas da lista de invocação:The following rules govern the equality of invocation list entries:

  • Se dois invocação entradas da lista os dois se referirem ao mesmo estático método e em seguida, as entradas são iguais.If two invocation list entries both refer to the same static method then the entries are equal.
  • Se dois invocação entradas da lista os dois se referirem ao mesmo método não estático no mesmo objeto de destino (conforme definido pelos operadores de igualdade de referência), em seguida, as entradas são iguais.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.
  • Entradas da lista de invocação produzido da avaliação de semanticamente idêntico anonymous_method_expressions ou lambda_expressions com o mesmo conjunto (possivelmente vazio) de variável externa capturada instâncias são permitidas (mas não obrigatórios) são iguais.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.

NULL e operadores de igualdadeEquality operators and null

O == e != operadores permitem um operando para ser um valor de um tipo anulável e outra para ser o null literal, mesmo se não existe nenhum operador predefinido ou definidos pelo usuário (no unlifted ou retirados de formulário) para a operação.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.

Para uma operação de uma das formasFor an operation of one of the forms

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

em que x é uma expressão de um tipo que permite valor nulo, se a resolução de sobrecarga de operador (resolução de sobrecarga de operador binário) Falha ao localizar um operador aplicável, o resultado em vez disso, é computada a partir de HasValue propriedade 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. Especificamente, os primeiros dois formulários são convertidos em !x.HasValue, e os últimos dois formulários são convertidos em x.HasValue.Specifically, the first two forms are translated into !x.HasValue, and last two forms are translated into x.HasValue.

O operador isThe is operator

O is operador é usado para verificar dinamicamente se o tipo de tempo de execução de um objeto é compatível com um determinado tipo.The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. O resultado da operação E is T, onde E é uma expressão e T é um tipo, é um booleano valor que indica se E pode ser convertido com êxito para o tipo T por uma conversão de referência, uma conversão boxing conversão, ou uma conversão 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. A operação é avaliada como a seguir, depois de argumentos de tipo tiverem sido substituídos para todos os parâmetros de tipo:The operation is evaluated as follows, after type arguments have been substituted for all type parameters:

  • Se E é uma função anônima, ocorre um erro de tempo de compilaçãoIf E is an anonymous function, a compile-time error occurs
  • Se E é um grupo de método ou o null literal, se o tipo de E é um tipo de referência ou um tipo anulável e o valor de E é nulo, o resultado é 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.
  • Caso contrário, deixe D representam o tipo dinâmico de E da seguinte maneira:Otherwise, let D represent the dynamic type of E as follows:
    • Se o tipo de E é um tipo de referência D é o tipo de tempo de execução da referência de instância por E.If the type of E is a reference type, D is the run-time type of the instance reference by E.
    • Se o tipo de E é um tipo anulável, D é o tipo subjacente desse tipo que permite valor nulo.If the type of E is a nullable type, D is the underlying type of that nullable type.
    • Se o tipo de E é um tipo de valor não anulável D é o tipo de E.If the type of E is a non-nullable value type, D is the type of E.
  • O resultado da operação depende D e T da seguinte maneira:The result of the operation depends on D and T as follows:
    • Se T é um tipo de referência, o resultado será true se D e T são do mesmo tipo, se D é um tipo de referência e uma conversão de referência implícita da D para T existe, ou se D é um tipo de valor e uma conversão de uma conversão boxing D para 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.
    • Se T é um tipo anulável, o resultado será true se D é o tipo subjacente de T.If T is a nullable type, the result is true if D is the underlying type of T.
    • Se T é um tipo de valor não anulável, o resultado será true se D e T são do mesmo tipo.If T is a non-nullable value type, the result is true if D and T are the same type.
    • Caso contrário, o resultado é false.Otherwise, the result is false.

Observe que as conversões definidas pelo usuário, não são consideradas pelo is operador.Note that user defined conversions, are not considered by the is operator.

O operadorThe as operator

O as operador é usado para converter explicitamente um valor para um tipo de referência fornecida ou tipo que permite valor nulo.The as operator is used to explicitly convert a value to a given reference type or nullable type. Ao contrário de uma expressão de conversão (expressões de conversão), o as operador nunca gera uma exceção.Unlike a cast expression (Cast expressions), the as operator never throws an exception. Em vez disso, se a conversão indicada não for possível, o valor resultante é null.Instead, if the indicated conversion is not possible, the resulting value is null.

Em uma operação do formulário E as T, E deve ser uma expressão e T deve ser um tipo de referência, um parâmetro de tipo conhecido por ser um tipo de referência ou um tipo anulável.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. Além disso, pelo menos uma das seguintes opções deve ser verdadeira ou, caso contrário, ocorrerá um erro de tempo de compilação:Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:

Se o tipo de tempo de compilação do E não é dynamic, a operação E as T produz o mesmo resultado 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

exceto que E é avaliado apenas uma vez.except that E is only evaluated once. O compilador pode ser esperado para otimizar E as T para executar no máximo uma verificação de tipo dinâmico em vez das duas verificações de tipo dinâmico implicado pela expansão acima.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.

Se o tipo de tempo de compilação do E é dynamic, diferentemente do operador cast as as operador não está vinculado dinamicamente (associação dinâmica).If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound (Dynamic binding). Portanto, a expansão nesse caso é:Therefore the expansion in this case is:

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

Observe que algumas conversões, como conversões definidas pelo usuário, não são possíveis com o as operador e, em vez disso, deve ser executada usando expressões de conversão.Note that some conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.

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

o parâmetro de tipo T de G é conhecido por ser um tipo de referência, porque ele tem a restrição de classe.the type parameter T of G is known to be a reference type, because it has the class constraint. O parâmetro de tipo U dos H não está no entanto; portanto, o uso das as operador em H não é permitido.The type parameter U of H is not however; hence the use of the as operator in H is disallowed.

Operadores lógicosLogical operators

O &, ^, e | operadores são chamados de operadores lógicos.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
    ;

Se um operando de um operador lógico tem o tipo de tempo de compilação dynamic, em seguida, a expressão está associada dinamicamente (vinculação dinâmica).If an operand of a logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Nesse caso é o tipo de tempo de compilação da expressão dynamic, e a resolução descrita a seguir ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que tenham o tipo de tempo de compilação 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.

Para uma operação do formulário x op y, onde op é um dos operadores lógicos, resolução de sobrecarga (resolução de sobrecarga de operador binário) é aplicado para selecionar uma implementação do operador específico.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. Os operandos são convertidos nos tipos de parâmetro do operador selecionado e o tipo do resultado é o tipo de retorno do operador.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.

Os operadores lógicos predefinidos são descritos nas seções a seguir.The predefined logical operators are described in the following sections.

Operadores lógicos de inteiroInteger logical operators

Os operadores lógicos de inteiro predefinidos são: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);

O & operador calcula o bit a bit lógicos AND dos dois operandos, o | operador calcula o bit a bit lógicos OR dos dois operandos e o ^ operador calcula o exclusivo lógico bit a bit OR dos dois operandos.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. Não há estouros são possíveis dessas operações.No overflows are possible from these operations.

Operadores lógicos de enumeraçãoEnumeration logical operators

Cada tipo de enumeração E implicitamente oferece operadores lógicos de predefinidas a seguir: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);

O resultado da avaliação x op y, onde x e y são expressões de um tipo de enumeração E com um tipo subjacente U, e op é um dos operadores lógicos, é exatamente o mesmo que Avaliando (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). Em outras palavras, os operadores lógicos de tipo de enumeração simplesmente executam a operação lógica no tipo subjacente dos dois operandos.In other words, the enumeration type logical operators simply perform the logical operation on the underlying type of the two operands.

Operadores lógicos boolianosBoolean logical operators

Os operadores lógicos boolianos predefinidos são:The predefined boolean logical operators are:

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

O resultado de x & y será true se ambos x e y forem true.The result of x & y is true if both x and y are true. Caso contrário, o resultado será false.Otherwise, the result is false.

O resultado de x | y está true se qualquer um dos x ou y é true.The result of x | y is true if either x or y is true. Caso contrário, o resultado será false.Otherwise, the result is false.

O resultado de x ^ y está true se x é true e y é false, ou x é false e y é true.The result of x ^ y is true if x is true and y is false, or x is false and y is true. Caso contrário, o resultado será false.Otherwise, the result is false. Quando os operandos forem do tipo bool, o ^ operador calcula o mesmo resultado que o != operador.When the operands are of type bool, the ^ operator computes the same result as the != operator.

Operadores lógicos boolianos que permitem valor nulosNullable boolean logical operators

O tipo de booliano anulável bool? pode representar os três valores, true, false, e nulle é conceitualmente semelhante ao tipo de três valores usado para expressões Boolianas em 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. Para garantir que os resultados produzidos pelos & e | operadores para bool? operandos são consistentes com a lógica de três valores do SQL, os seguintes operadores predefinidos são fornecidos: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);

A tabela a seguir lista os resultados produzidos por esses operadores para todas as combinações dos valores true, false, e 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

Operadores lógicos condicionaisConditional logical operators

O && e || operadores são chamados de operadores lógicos condicionais.The && and || operators are called the conditional logical operators. Eles também são chamados de operadores lógicos "curto-circuito".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
    ;

O && e || operadores são versões condicionais da & e | operadores:The && and || operators are conditional versions of the & and | operators:

  • A operação x && y corresponde à operação x & y, exceto pelo fato y é avaliada apenas se x não é false.The operation x && y corresponds to the operation x & y, except that y is evaluated only if x is not false.
  • A operação x || y corresponde à operação x | y, exceto pelo fato y é avaliada apenas se x não é true.The operation x || y corresponds to the operation x | y, except that y is evaluated only if x is not true.

Se um operando de um operador lógico condicional tem o tipo de tempo de compilação dynamic, em seguida, a expressão está associada dinamicamente (vinculação dinâmica).If an operand of a conditional logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). Nesse caso é o tipo de tempo de compilação da expressão dynamic, e a resolução descrita a seguir ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que tenham o tipo de tempo de compilação 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.

Uma operação do formulário x && y ou x || y é processada por meio da aplicação de resolução de sobrecarga (resolução de sobrecarga de operador binário) como se a operação foi escrita 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. Em seguida,Then,

Não é possível sobrecarregar diretamente os operadores lógicos condicionais.It is not possible to directly overload the conditional logical operators. No entanto, porque os operadores lógicos condicionais são avaliados em termos de operadores lógicos regulares, sobrecargas dos operadores lógicos regulares, com algumas restrições, também são consideradas sobrecargas dos operadores lógicos condicionais.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. Isso é descrito posteriormente em operadores lógicos condicionais definidos pelo usuário.This is described further in User-defined conditional logical operators.

Boolianos operadores lógicos condicionaisBoolean conditional logical operators

Quando os operandos de && ou || são do tipo bool, ou quando os operandos forem de tipos que não definem um aplicável operator & ou operator |, mas definir conversões implícitas para bool, a operação é processado da seguinte maneira: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:

  • A operação x && y é avaliada como x ? y : false.The operation x && y is evaluated as x ? y : false. Em outras palavras, x é avaliado primeiro e convertido no tipo bool.In other words, x is first evaluated and converted to type bool. Então, se x está true, y é avaliada e convertido no tipo bool, e isso se torna o resultado da operação.Then, if x is true, y is evaluated and converted to type bool, and this becomes the result of the operation. Caso contrário, o resultado da operação é false.Otherwise, the result of the operation is false.
  • A operação x || y é avaliada como x ? true : y.The operation x || y is evaluated as x ? true : y. Em outras palavras, x é avaliado primeiro e convertido no tipo bool.In other words, x is first evaluated and converted to type bool. Então, se x está true, o resultado da operação é true.Then, if x is true, the result of the operation is true. Caso contrário, y é avaliado e convertido no tipo bool, e isso se torna o resultado da operação.Otherwise, y is evaluated and converted to type bool, and this becomes the result of the operation.

Operadores lógicos condicionais definidos pelo usuárioUser-defined conditional logical operators

Quando os operandos de && ou || são de tipos que declaram um aplicável definidos pelo usuário operator & ou operator |, ambos os seguintes procedimentos devem ser verdadeiras, onde T é o tipo no qual o operador selecionado é declarado: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:

  • O tipo de retorno e o tipo de cada parâmetro do operador selecionado devem ser T.The return type and the type of each parameter of the selected operator must be T. Em outras palavras, o operador deve calcular o lógico AND ou a lógica OR de dois operandos do tipo Te deve retornar um resultado do tipo 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 deve conter declarações de operator true e operator false.T must contain declarations of operator true and operator false.

Ocorrerá um erro de tempo de associação se esses requisitos não for atendida.A binding-time error occurs if either of these requirements is not satisfied. Caso contrário, o && ou || operação é calculada pela combinação de definido pelo usuário operator true ou operator false com o operador selecionado definido pelo usuário:Otherwise, the && or || operation is evaluated by combining the user-defined operator true or operator false with the selected user-defined operator:

  • A operação x && y é avaliado como T.false(x) ? x : T.&(x, y), onde T.false(x) é uma invocação dos operator false declarado no T, e T.&(x, y) é uma invocação do selecionado operator &.The operation x && y is evaluated as T.false(x) ? x : T.&(x, y), where T.false(x) is an invocation of the operator false declared in T, and T.&(x, y) is an invocation of the selected operator &. Em outras palavras, x é avaliado primeiro e operator false é invocado no resultado para determinar se x é, definitivamente, false.In other words, x is first evaluated and operator false is invoked on the result to determine if x is definitely false. Então, se x é definitivamente false, o resultado da operação é o valor calculado anteriormente para x.Then, if x is definitely false, the result of the operation is the value previously computed for x. Caso contrário, y é avaliada e selecionado operator & é invocado no valor calculado anteriormente para x e o valor calculado para y para produzir o resultado da operação.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.
  • A operação x || y é avaliado como T.true(x) ? x : T.|(x, y), onde T.true(x) é uma invocação dos operator true declarado no T, e T.|(x,y) é uma invocação do selecionado operator|.The operation x || y is evaluated as T.true(x) ? x : T.|(x, y), where T.true(x) is an invocation of the operator true declared in T, and T.|(x,y) is an invocation of the selected operator|. Em outras palavras, x é avaliado primeiro e operator true é invocado no resultado para determinar se x é definitivamente verdade.In other words, x is first evaluated and operator true is invoked on the result to determine if x is definitely true. Então, se x é definitivamente verdade, o resultado da operação é o valor calculado anteriormente para x.Then, if x is definitely true, the result of the operation is the value previously computed for x. Caso contrário, y é avaliada e selecionado operator | é invocado no valor calculado anteriormente para x e o valor calculado para y para produzir o resultado da operação.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.

Em qualquer uma dessas operações, a expressão fornecida pelo x só é avaliada uma vez e a expressão fornecida pelo y não é avaliada ou avaliada apenas uma vez.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.

Para obter um exemplo de um tipo que implementa operator true e operator false, consulte banco de dados tipo booliano.For an example of a type that implements operator true and operator false, see Database boolean type.

O operador de união nuloThe null coalescing operator

O ?? operador é chamado de operador de união nulo.The ?? operator is called the null coalescing operator.

null_coalescing_expression
    : conditional_or_expression
    | conditional_or_expression '??' null_coalescing_expression
    ;

Uma expressão de união nula do formulário a ?? b requer a para ser de um tipo que permite valor nulo de tipo ou referência.A null coalescing expression of the form a ?? b requires a to be of a nullable type or reference type. Se a não for nulo, o resultado da a ?? b é a; caso contrário, o resultado é b.If a is non-null, the result of a ?? b is a; otherwise, the result is b. A operação avalia b somente se a é nulo.The operation evaluates b only if a is null.

O operador de união nulo é associativo à direita, o que significa que as operações são agrupadas da direita para esquerda.The null coalescing operator is right-associative, meaning that operations are grouped from right to left. Por exemplo, uma expressão do formulário a ?? b ?? c é avaliada como a ?? (b ?? c).For example, an expression of the form a ?? b ?? c is evaluated as a ?? (b ?? c). Termos em geral, uma expressão do formulário E1 ?? E2 ?? ... ?? En retorna o primeiro dos operandos for não nulo, ou nulo se todos os operandos são nulos.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.

O tipo da expressão a ?? b depende de quais conversões implícitas estão disponíveis nos operandos.The type of the expression a ?? b depends on which implicit conversions are available on the operands. Ordem de preferência, o tipo de a ?? b está A0, A, ou B, onde A é o tipo de a (desde que a tem um tipo), B é o tipo de b ( desde que b tem um tipo), e A0 é o tipo subjacente de A se A é um tipo anulável, ou A caso contrário.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. Especificamente, a ?? b é processado da seguinte maneira:Specifically, a ?? b is processed as follows:

  • Se A existe e não é um tipo anulável ou um tipo de referência, ocorre um erro de tempo de compilação.If A exists and is not a nullable type or a reference type, a compile-time error occurs.
  • Se b é uma expressão dinâmica, o tipo de resultado é dynamic.If b is a dynamic expression, the result type is dynamic. Em tempo de execução, a é avaliada primeiro.At run-time, a is first evaluated. Se a não for nulo, a é convertido para dinâmico, e isso se torna o resultado.If a is not null, a is converted to dynamic, and this becomes the result. Caso contrário, b é avaliada, e isso se torna o resultado.Otherwise, b is evaluated, and this becomes the result.
  • Caso contrário, se A existe e é um tipo anulável e existe uma conversão implícita da b à A0, o tipo de resultado é A0.Otherwise, if A exists and is a nullable type and an implicit conversion exists from b to A0, the result type is A0. Em tempo de execução, a é avaliada primeiro.At run-time, a is first evaluated. Se a não for null, a é desencapsulado para o tipo A0, e isso se torna o resultado.If a is not null, a is unwrapped to type A0, and this becomes the result. Caso contrário, b é avaliado e convertido no tipo A0, e isso se torna o resultado.Otherwise, b is evaluated and converted to type A0, and this becomes the result.
  • Caso contrário, se A existe e existe uma conversão implícita da b à A, o tipo de resultado é A.Otherwise, if A exists and an implicit conversion exists from b to A, the result type is A. Em tempo de execução, a é avaliada primeiro.At run-time, a is first evaluated. Se a não for nulo, a se tornará o resultado.If a is not null, a becomes the result. Caso contrário, b é avaliado e convertido no tipo A, e isso se torna o resultado.Otherwise, b is evaluated and converted to type A, and this becomes the result.
  • Caso contrário, se b tem um tipo B e existe uma conversão implícita de a à B, o tipo de resultado é B.Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. Em tempo de execução, a é avaliada primeiro.At run-time, a is first evaluated. Se a não for null, a é desencapsulado para o tipo A0 (se A existe e é anulável) e convertido para o tipo B, e isso se torna o resultado.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. Caso contrário, b é avaliada e torna-se o resultado.Otherwise, b is evaluated and becomes the result.
  • Caso contrário, a e b são incompatíveis e um erro de tempo de compilação ocorre.Otherwise, a and b are incompatible, and a compile-time error occurs.

Operador condicionalConditional operator

O ?: operador é chamado de operador condicional.The ?: operator is called the conditional operator. Ele às vezes também é chamado de operador ternário.It is at times also called the ternary operator.

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

Uma expressão condicional do formulário b ? x : y primeiro avalia a condição b.A conditional expression of the form b ? x : y first evaluates the condition b. Então, se b está true, x é avaliada e torna-se o resultado da operação.Then, if b is true, x is evaluated and becomes the result of the operation. Caso contrário, y é avaliada e torna-se o resultado da operação.Otherwise, y is evaluated and becomes the result of the operation. Uma expressão condicional é avaliada nunca ambos x e y.A conditional expression never evaluates both x and y.

O operador condicional é associativo à direita, o que significa que as operações são agrupadas da direita para esquerda.The conditional operator is right-associative, meaning that operations are grouped from right to left. Por exemplo, uma expressão do formulário a ? b : c ? d : e é avaliada como 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).

O primeiro operando do ?: operador deve ser uma expressão que pode ser convertida implicitamente em bool, ou uma expressão de um tipo que implementa 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. Se nenhum desses requisitos é atendido, ocorrerá um erro de tempo de compilação.If neither of these requirements is satisfied, a compile-time error occurs.

O segundo e terceiro operandos, x e y, da ?: operador controlam o tipo da expressão condicional.The second and third operands, x and y, of the ?: operator control the type of the conditional expression.

  • Se x tem o tipo X e y tem o tipo Y , em seguida,If x has type X and y has type Y then
    • Se uma conversão implícita (conversões implícitas) existe a partir de X para Y, mas não de Y para X, em seguida, Y é o tipo da expressão condicional.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.
    • Se uma conversão implícita (conversões implícitas) existe a partir de Y para X, mas não de X para Y, em seguida, X é o tipo da expressão condicional.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.
    • Caso contrário, nenhum tipo de expressão pode ser determinado, e ocorre um erro de tempo de compilação.Otherwise, no expression type can be determined, and a compile-time error occurs.
  • Se apenas um dos x e y tem um tipo e ambos x e y, de são implicitamente conversíveis para esse tipo, em seguida, o que é o tipo da expressão condicional.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.
  • Caso contrário, nenhum tipo de expressão pode ser determinado, e ocorre um erro de tempo de compilação.Otherwise, no expression type can be determined, and a compile-time error occurs.

O processamento de tempo de execução de uma expressão condicional do formulário b ? x : y consiste as seguintes etapas:The run-time processing of a conditional expression of the form b ? x : y consists of the following steps:

  • Primeiro, b é avaliada e o bool valor b é determinado:First, b is evaluated, and the bool value of b is determined:
    • Se uma conversão implícita do tipo de b à bool existir, essa conversão implícita é executada para produzir um bool valor.If an implicit conversion from the type of b to bool exists, then this implicit conversion is performed to produce a bool value.
    • Caso contrário, o operator true definidos pelo tipo de b é invocado para produzir um bool valor.Otherwise, the operator true defined by the type of b is invoked to produce a bool value.
  • Se o bool valor produzido pela etapa anterior está true, em seguida, x é avaliada e convertida no tipo de expressão condicional, e isso se torna o resultado da expressão condicional.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.
  • Caso contrário, y é avaliada e convertida no tipo de expressão condicional, e isso se torna o resultado da expressão condicional.Otherwise, y is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.

Expressões de função anônimaAnonymous function expressions

Uma função anônima é uma expressão que representa uma definição de método "na linha".An anonymous function is an expression that represents an "in-line" method definition. Uma função anônima não tem um valor ou tipo por si só, mas pode ser convertido em um tipo de árvore de expressão ou delegado compatível.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. A avaliação de uma conversão de função anônima depende do tipo de destino da conversão: Se for um tipo de delegado, a conversão é avaliada como um valor de delegado fizer referência ao método que define a função anônima.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. Se for um tipo de árvore de expressão, a conversão é avaliada como uma árvore de expressão que representa a estrutura do método como uma estrutura de objeto.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.

Por razões históricas existem dois tipos sintáticos de funções anônimas, ou seja, lambda_expressions e anonymous_method_expressions.For historical reasons there are two syntactic flavors of anonymous functions, namely lambda_expressions and anonymous_method_expressions. Para fins de quase todos os lambda_expressions são mais concisas e expressivo que anonymous_method_expressions, que permanecem no idioma para compatibilidade com versões anteriores.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
    ;

O => operador tem a mesma precedência que a atribuição (=) e é associativo à direita.The => operator has the same precedence as assignment (=) and is right-associative.

Uma função anônima com o async modificador é uma função assíncrona e segue as regras descritas em iteradores.An anonymous function with the async modifier is an async function and follows the rules described in Iterators.

Os parâmetros de uma função anônima na forma de um lambda_expression podem ser explicitamente ou implicitamente digitados.The parameters of an anonymous function in the form of a lambda_expression can be explicitly or implicitly typed. Em uma lista de parâmetros de tipo explícito, o tipo de cada parâmetro é explicitamente declarado.In an explicitly typed parameter list, the type of each parameter is explicitly stated. Em uma lista de parâmetros de tipo implícito, os tipos dos parâmetros são inferidos do contexto no qual ocorre a função anônima — especificamente, quando a função anônima é convertida em um tipo de delegado compatível ou tipo de árvore de expressão, que fornece o tipo os tipos de parâmetro (conversões de função anônima).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).

Em uma função anônima com um parâmetro de tipo implícito, único, os parênteses que podem ser omitidos da lista de parâmetros.In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. Em outras palavras, uma função anônima do formulárioIn other words, an anonymous function of the form

( param ) => expr

pode ser abreviado comocan be abbreviated to

param => expr

Lista de parâmetros de uma função anônima na forma de um anonymous_method_expression é opcional.The parameter list of an anonymous function in the form of an anonymous_method_expression is optional. Se for especificado, os parâmetros devem ser digitados explicitamente.If given, the parameters must be explicitly typed. Se não, a função anônima é convertida em um delegado com qualquer parâmetro de lista não contêm out parâmetros.If not, the anonymous function is convertible to a delegate with any parameter list not containing out parameters.

Um bloco corpo de uma função anônima é acessível (pontos de extremidade e acessibilidade), a menos que a função anônima ocorre dentro de uma instrução inacessível.A block body of an anonymous function is reachable (End points and reachability) unless the anonymous function occurs inside an unreachable statement.

Seguem alguns exemplos de funções anônimas abaixo: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

O comportamento de lambda_expressions e anonymous_method_expressions é o mesmo, exceto para os seguintes pontos:The behavior of lambda_expressions and anonymous_method_expressions is the same except for the following points:

  • anonymous_method_expressions permitir que a lista de parâmetros a serem omitidos totalmente, produzindo a convertibilidade de tipos de qualquer lista de parâmetros com valor de delegado.anonymous_method_expressions permit the parameter list to be omitted entirely, yielding convertibility to delegate types of any list of value parameters.
  • lambda_expressions permite que os tipos de parâmetro seja omitido e inferido, enquanto anonymous_method_expressions exigem tipos de parâmetro a ser declarado explicitamente.lambda_expressions permit parameter types to be omitted and inferred whereas anonymous_method_expressions require parameter types to be explicitly stated.
  • O corpo de uma lambda_expression pode ser uma expressão ou um bloco de instruções enquanto o corpo de uma anonymous_method_expression deve ser um bloco de instruções.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.
  • Somente lambda_expressions têm conversões para tipos de árvore de expressão compatível (tipos de árvore de expressão).Only lambda_expressions have conversions to compatible expression tree types (Expression tree types).

Assinaturas de função anônimaAnonymous function signatures

Opcional anonymous_function_signature de uma função anônima define os nomes e, opcionalmente, os tipos dos parâmetros formais para a função anônima.The optional anonymous_function_signature of an anonymous function defines the names and optionally the types of the formal parameters for the anonymous function. O escopo dos parâmetros de função anônima que é o anonymous_function_body.The scope of the parameters of the anonymous function is the anonymous_function_body. (Escopos) junto com a lista de parâmetros (se fornecida) anônima-corpo do método-constitui um espaço de declaração (declarações).(Scopes) Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space (Declarations). Ele é, portanto, um erro de tempo de compilação para o nome de um parâmetro da função anônima para corresponder ao nome de uma variável local, a constante local ou parâmetro cujo escopo inclui o anonymous_method_expression ou lambda_ expressão.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.

Se uma função anônima tem uma explicit_anonymous_function_signature, em seguida, o conjunto de tipos de delegado compatível e tipos de árvore de expressão é restrito para aqueles que têm os mesmos tipos de parâmetro e modificadores na mesma ordem.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. Em contraste com conversões de grupo de método (conversões de grupo de método), não há suporte para a contravariância dos tipos de parâmetro de função anônima.In contrast to method group conversions (Method group conversions), contra-variance of anonymous function parameter types is not supported. Se uma função anônima não tem um anonymous_function_signature, em seguida, o conjunto de tipos de delegado compatível e tipos de árvore de expressão é restrito para aqueles que não têm nenhum out parâmetros.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.

Observe que um anonymous_function_signature não pode incluir atributos ou uma matriz de parâmetros.Note that an anonymous_function_signature cannot include attributes or a parameter array. No entanto, uma anonymous_function_signature podem ser compatíveis com um tipo de delegado cuja lista de parâmetros contém uma matriz de parâmetros.Nevertheless, an anonymous_function_signature may be compatible with a delegate type whose parameter list contains a parameter array.

Observe também que conversão para um tipo de árvore de expressão, mesmo se compatível, ainda pode falhar em tempo de compilação (tipos de árvore de expressão).Note also that conversion to an expression tree type, even if compatible, may still fail at compile-time (Expression tree types).

Corpos de função anônimaAnonymous function bodies

O corpo (expressão ou bloco) de uma função anônima é sujeito às seguintes regras:The body (expression or block) of an anonymous function is subject to the following rules:

  • Se a função anônima inclui uma assinatura, os parâmetros especificados na assinatura estão disponíveis no corpo.If the anonymous function includes a signature, the parameters specified in the signature are available in the body. Se a função anônima não tiver uma assinatura pode ser convertido para um tipo de delegado ou ter parâmetros de tipo de expressão (conversões de função anônima), mas os parâmetros não podem ser acessados no corpo.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.
  • Exceto para ref ou out parâmetros especificados na assinatura (se houver) do delimitador mais próximo função anônima, ele é um erro de tempo de compilação para o corpo acessar um ref ou out parâmetro.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.
  • Quando o tipo de this é um tipo de struct, ele é um erro de tempo de compilação para o corpo acessar this.When the type of this is a struct type, it is a compile-time error for the body to access this. Isso é verdadeiro se o acesso é explícito (como em this.x) ou implícita (como na x onde x é um membro de instância do 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). Essa regra simplesmente proíbe tal acesso e não afeta se a pesquisa de membro resulta em um membro do struct.This rule simply prohibits such access and does not affect whether member lookup results in a member of the struct.
  • O corpo da tem acesso a variáveis externas (Outer variáveis) da função anônima.The body has access to the outer variables (Outer variables) of the anonymous function. Acesso de uma variável externa fará referência a instância da variável que está ativo no momento a lambda_expression ou anonymous_method_expression é avaliada (avaliação do expressões de função anônima).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).
  • É um erro de tempo de compilação para o corpo conter um goto instrução break instrução, ou continue cujo destino está fora do corpo ou dentro do corpo de uma função anônima contida.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.
  • Um return no corpo da declaração de uma invocação de delimitadora mais próxima função anônima, não do membro da função de circunscrição.A return statement in the body returns control from an invocation of the nearest enclosing anonymous function, not from the enclosing function member. Uma expressão especificada em uma return instrução deve ser implicitamente conversível para o tipo de retorno do tipo de delegado ou tipo de árvore de expressão para o qual delimitadora mais próxima lambda_expression ou anonymous_ method_expression é convertido (conversões de função anônima).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).

Ele não é especificado explicitamente se há alguma maneira de executar o bloco de uma função anônima diferente por meio de avaliação e invocação do 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. Em particular, o compilador pode optar por implementar uma função anônima por sintetizar um ou mais nomeadas tipos ou métodos.In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types. Os nomes de todos esses elementos sintetizados devem ser de um formulário reservado para uso pelo compilador.The names of any such synthesized elements must be of a form reserved for compiler use.

Resolução de sobrecarga e funções anônimasOverload resolution and anonymous functions

Funções anônimas em uma lista de argumentos participarem de inferência de tipo e resolução de sobrecarga.Anonymous functions in an argument list participate in type inference and overload resolution. Consulte a inferência e resolução de sobrecarga para as regras exatas.Please refer to Type inference and Overload resolution for the exact rules.

O exemplo a seguir ilustra o efeito de funções anônimas em resolução de sobrecarga.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;
    }
}

O ItemList<T> classe tem duas Sum métodos.The ItemList<T> class has two Sum methods. Cada um leva um selector argumento, que extrai o valor a soma ao longo de um item de lista.Each takes a selector argument, which extracts the value to sum over from a list item. O valor extraído pode ser um int ou um double e a soma resultante é da mesma forma uma int ou um double.The extracted value can be either an int or a double and the resulting sum is likewise either an int or a double.

O Sum métodos, por exemplo poderiam ser usados para calcular somas em uma lista de linhas de detalhes em uma ordem.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);
    ...
}

Na primeira invocação de orderDetails.Sum, ambos Sum métodos são aplicáveis porque a função anônima d => d. UnitCount é compatível com ambos Func<Detail,int> e 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>. No entanto, a resolução de sobrecarga seleciona a primeira Sum método porque a conversão para o Func<Detail,int> é melhor do que a conversão em 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>.

Na segunda chamada de orderDetails.Sum, apenas o segundo Sum método é aplicável porque a função anônima d => d.UnitPrice * d.UnitCount produz um valor do tipo 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. Portanto, sobrecarregar resolução escolhe o segundo Sum método para essa invocação.Thus, overload resolution picks the second Sum method for that invocation.

Funções anônimas e vinculação dinâmicaAnonymous functions and dynamic binding

Uma função anônima não pode ser um receptor, o argumento ou operando de uma operação dinâmica associada.An anonymous function cannot be a receiver, argument or operand of a dynamically bound operation.

Variáveis externasOuter variables

Qualquer variável local, um parâmetro de valor ou uma matriz de parâmetros cujo escopo inclui o lambda_expression ou anonymous_method_expression é chamado um variável externa da função anônima.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. Em um membro da função de instância de uma classe, o this valor é considerado um parâmetro de valor e é uma variável externa de qualquer função anônima contida dentro do membro da função.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.

Capturado variáveis externasCaptured outer variables

Quando uma variável externa é referenciada por uma função anônima, a variável externa deve ter sido capturados pela função anônima.When an outer variable is referenced by an anonymous function, the outer variable is said to have been captured by the anonymous function. Normalmente, o tempo de vida de uma variável local é limitado à execução de instrução ao qual ele está associado ou bloco (variáveis locais).Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated (Local variables). No entanto, o tempo de vida de uma variável externa capturada é estendido pelo menos até que o delegado ou árvore de expressão criada a partir da função anônima se qualifique para coleta de lixo.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.

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

a variável local x for capturada, a função anônima e a vida útil do x é estendido pelo menos até que o delegado retornado F se qualifique para coleta de lixo (que não acontece até o final do o programa).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). Uma vez que cada invocação de função anônima que opera na mesma instância de x, a saída do exemplo é:Since each invocation of the anonymous function operates on the same instance of x, the output of the example is:

1
2
3

Quando uma variável local ou um parâmetro de valor é capturado por uma função anônima, o parâmetro ou variável local não é mais considerado para ser uma variável fixa (fixo e variáveis moveable), mas em vez disso, é considerado como um moveable variável.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. Assim, qualquer unsafe código que usa o endereço de uma variável externa capturada primeiro deve usar o fixed instrução para corrigir a variável.Thus any unsafe code that takes the address of a captured outer variable must first use the fixed statement to fix the variable.

Observe que, ao contrário de uma variável uncaptured, uma variável de local capturada pode ser exposta simultaneamente para vários threads de execução.Note that unlike an uncaptured variable, a captured local variable can be simultaneously exposed to multiple threads of execution.

Instanciação de variáveis locaisInstantiation of local variables

Uma variável local é considerada instanciado quando execução entra no escopo da variável.A local variable is considered to be instantiated when execution enters the scope of the variable. Por exemplo, quando o método a seguir é invocado, a variável local x é instanciada e inicializado três vezes — uma vez para cada iteração do loop.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;
        ...
    }
}

No entanto, mover a declaração de x fora os resultados de loop em uma única instanciação 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;
        ...
    }
}

Quando não capturada, não há nenhuma maneira de observar exatamente a frequência com que uma variável local é instanciada — como os tempos de vida as instanciações são não contíguos, é possível para cada instanciação simplesmente usar o mesmo local de armazenamento.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. No entanto, quando uma função anônima captura uma variável local, os efeitos de instanciação se tornam aparentes.However, when an anonymous function captures a local variable, the effects of instantiation become apparent.

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

produz a saída:produces the output:

1
3
5

No entanto, quando a declaração de x é movido para fora do loop: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;
}

A saída é:the output is:

5
5
5

Se um loop for declarar uma variável de iteração, essa variável em si é considerado declarado fora do loop.If a for-loop declares an iteration variable, that variable itself is considered to be declared outside of the loop. Portanto, se o exemplo é modificado para capturar a variável de iteração: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;
}

apenas uma instância de variável de iteração é capturada, que produz a saída:only one instance of the iteration variable is captured, which produces the output:

3
3
3

É possível que os delegados de função anônima para compartilhar algumas variáveis capturadas ainda tem instâncias separadas de outras pessoas.It is possible for anonymous function delegates to share some captured variables yet have separate instances of others. Por exemplo, se F é alterado paraFor 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;
}

os três delegados capturam a mesma instância do x mas instâncias separadas do y, e a saída é:the three delegates capture the same instance of x but separate instances of y, and the output is:

1 1
2 1
3 1

Funções anônimas separadas podem capturar a mesma instância de uma variável externa.Separate anonymous functions can capture the same instance of an outer variable. No exemplo: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());
    }
}

as duas funções anônimas capturam a mesma instância da variável local x, e eles podem, portanto, "se comunicar" por meio dessa variável.the two anonymous functions capture the same instance of the local variable x, and they can thus "communicate" through that variable. A saída do exemplo é:The output of the example is:

5
10

Avaliação de expressões de função anônimaEvaluation of anonymous function expressions

Uma função anônima F sempre deve ser convertido em um tipo de delegado D ou um tipo de árvore de expressão E, diretamente ou por meio da execução de uma expressão de criação de delegado 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). Essa conversão determina o resultado da função anônima, conforme descrito na conversões de função anônima.This conversion determines the result of the anonymous function, as described in Anonymous function conversions.

Expressões de consultaQuery expressions

Expressões de consulta fornecem uma sintaxe de linguagem integrada para consultas que é semelhante a linguagens de consulta relacionais e hierárquicas, como SQL e 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
    ;

Uma expressão de consulta começa com um from cláusula e termina com um uma select ou group cláusula.A query expression begins with a from clause and ends with either a select or group clause. Inicial from cláusula pode ser seguida por zero ou mais from, let, where, join ou orderby cláusulas.The initial from clause can be followed by zero or more from, let, where, join or orderby clauses. Cada from cláusula é um gerador de introduzir uma variável de intervalo que abrange os elementos de uma sequência.Each from clause is a generator introducing a range variable which ranges over the elements of a sequence. Cada let cláusula introduz uma variável de intervalo que representa um valor calculado por meio de variáveis de intervalo anterior.Each let clause introduces a range variable representing a value computed by means of previous range variables. Cada where cláusula é um filtro que exclui itens de resultado.Each where clause is a filter that excludes items from the result. Cada join cláusula compara as chaves especificadas da sequência de origem com chaves de outra sequência, resultando em pares correspondentes.Each join clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. Cada orderby cláusula reordena os itens de acordo com os critérios especificados. O último select ou group cláusula Especifica a forma do resultado em termos de variáveis de intervalo.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. Por fim, um into cláusula pode ser usada para "unir" consultas, tratando os resultados de uma consulta como um gerador em uma consulta subsequente.Finally, an into clause can be used to "splice" queries by treating the results of one query as a generator in a subsequent query.

Ambiguidades em expressões de consultaAmbiguities in query expressions

Expressões de consulta contêm um número de "palavras-chave contextuais", ou seja, os identificadores que têm significado especial em um determinado contexto.Query expressions contain a number of "contextual keywords", i.e., identifiers that have special meaning in a given context. Especificamente, esses são from, where, join, on, equals, into, let, orderby, ascending, descending, select, group e by.Specifically these are from, where, join, on, equals, into, let, orderby, ascending, descending, select, group and by. Para evitar ambiguidades em expressões de consulta causadas pelo uso misto desses identificadores como nomes simples ou palavras-chave, esses identificadores são considerados palavras-chave quando que ocorrem em qualquer lugar dentro de uma expressão de consulta.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.

Para essa finalidade, uma expressão de consulta é qualquer expressão que começa com "from identifier"seguido por qualquer token exceto";","="ou",".For this purpose, a query expression is any expression that starts with "from identifier" followed by any token except ";", "=" or ",".

Para usar essas palavras como identificadores em uma expressão de consulta, elas podem ser prefixadas com "@" (identificadores).In order to use these words as identifiers within a query expression, they can be prefixed with "@" (Identifiers).

Conversão de expressão de consultaQuery expression translation

A linguagem c# não especifica a semântica de execução de expressões de consulta.The C# language does not specify the execution semantics of query expressions. Em vez disso, as expressões de consulta são traduzidas para invocações de métodos que seguem a padrão de expressão de consulta (o padrão de expressão de consulta).Rather, query expressions are translated into invocations of methods that adhere to the query expression pattern (The query expression pattern). Especificamente, as expressões de consulta são convertidas em chamadas de métodos chamados Where, Select, SelectMany, Join, GroupJoin, OrderBy, OrderByDescending, ThenBy, ThenByDescending, GroupBy, e Cast. Esses métodos devem ter assinaturas específicas e tipos de resultado, conforme descrito em o padrão de expressão de consulta.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. Esses métodos podem ser métodos de instância do objeto que está sendo consultada ou métodos de extensão que são externos ao objeto, e elas implementam a execução real da consulta.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.

A tradução de expressões de consulta para invocações de método é um mapeamento sintático que ocorre antes de qualquer tipo de associação ou resolução de sobrecarga foi executada.The translation from query expressions to method invocations is a syntactic mapping that occurs before any type binding or overload resolution has been performed. A tradução é garantida para ser sintaticamente correto, mas não é garantido para produzir o código c# semanticamente correto.The translation is guaranteed to be syntactically correct, but it is not guaranteed to produce semantically correct C# code. Após a conversão de expressões de consulta, invocações de método resultantes são processadas como invocações de método normal, e isso por sua vez pode revelar erros, por exemplo, se os métodos não existem, se os argumentos têm tipos errados ou se os métodos são genéricos e Falha de inferência de tipo.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.

Uma expressão de consulta é processada aplicando as seguintes traduções repetidamente até que nenhum reduções ainda maiores são possíveis.A query expression is processed by repeatedly applying the following translations until no further reductions are possible. As traduções estão listadas na ordem do aplicativo: cada seção pressupõe que as traduções nas seções anteriores foram executadas exaustivamente e depois que esgotar, uma seção será não mais tarde revista no processamento da mesma expressão de consulta.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.

Atribuição a variáveis de intervalo não é permitida em expressões de consulta.Assignment to range variables is not allowed in query expressions. No entanto, uma implementação c# é permitida para nem sempre impõe esta restrição, uma vez que isso pode às vezes, não ser possível com o esquema de tradução sintática apresentado aqui.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.

Determinadas conversões inserir variáveis de intervalo com identificadores transparentes indicados por *.Certain translations inject range variables with transparent identifiers denoted by *. As propriedades especiais de transparentes identificadores são discutidas mais detalhadamente em transparentes identificadores.The special properties of transparent identifiers are discussed further in Transparent identifiers.

Cláusulas SELECT e groupby com continuaçõesSelect and groupby clauses with continuations

Uma expressão de consulta com uma continuaçãoA query expression with a continuation

from ... into x ...

é convertido emis translated into

from x in ( from ... ) ...

As traduções nas seções a seguir supõem que não têm consultas into continuações.The translations in the following sections assume that queries have no into continuations.

O exemploThe example

from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }

é convertido emis translated into

from g in
    from c in customers
    group c by c.Country
select new { Country = g.Key, CustCount = g.Count() }

a tradução final que éthe final translation of which is

customers.
GroupBy(c => c.Country).
Select(g => new { Country = g.Key, CustCount = g.Count() })

Tipos de variável de intervalo explícitoExplicit range variable types

Um from cláusula que especifica explicitamente um tipo de variável de intervaloA from clause that explicitly specifies a range variable type

from T x in e

é convertido emis translated into

from x in ( e ) . Cast < T > ( )

Um join cláusula que especifica explicitamente um tipo de variável de intervaloA join clause that explicitly specifies a range variable type

join T x in e on k1 equals k2

é convertido emis translated into

join x in ( e ) . Cast < T > ( ) on k1 equals k2

As traduções nas seções a seguir pressupõem que o consultas não tem nenhum tipo de variável de intervalo explícito.The translations in the following sections assume that queries have no explicit range variable types.

O exemploThe example

from Customer c in customers
where c.City == "London"
select c

é convertido emis translated into

from c in customers.Cast<Customer>()
where c.City == "London"
select c

a tradução final que éthe final translation of which is

customers.
Cast<Customer>().
Where(c => c.City == "London")

Tipos de variável de intervalo explícitas são úteis para consultar coleções que implementam não genéricas IEnumerable interface, mas não genérica IEnumerable<T> interface.Explicit range variable types are useful for querying collections that implement the non-generic IEnumerable interface, but not the generic IEnumerable<T> interface. No exemplo acima, isso seria o caso se customers eram do tipo ArrayList.In the example above, this would be the case if customers were of type ArrayList.

Expressões de consulta de degeneraçãoDegenerate query expressions

Uma expressão de consulta do formulárioA query expression of the form

from x in e select x

é convertido emis translated into

( e ) . Select ( x => x )

O exemploThe example

from c in customers
select c

é convertido emis translated into

customers.Select(c => c)

Uma expressão de consulta degenerado é aquele que trivialmente seleciona os elementos da fonte.A degenerate query expression is one that trivially selects the elements of the source. Uma fase posterior da tradução remove degeneradas consultas introduzidas por outras etapas de tradução, substituindo-os à sua origem.A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. É importante no entanto, para garantir que o resultado de uma consulta de expressão nunca é o objeto de origem em si, como o que poderia revelar o tipo e a identidade da origem para o cliente da consulta.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. Nesta etapa, portanto, protege os degenerado consultas gravadas diretamente no código-fonte chamando explicitamente Select na origem.Therefore this step protects degenerate queries written directly in source code by explicitly calling Select on the source. Ele cabe, em seguida, os implementadores de Select e outros operadores de consulta para garantir que esses métodos nunca retornam o objeto de origem.It is then up to the implementers of Select and other query operators to ensure that these methods never return the source object itself.

Do, where, orderby e junção cláusulas letFrom, let, where, join and orderby clauses

Uma expressão de consulta com uma segunda from cláusula seguido por um select cláusulaA query expression with a second from clause followed by a select clause

from x1 in e1
from x2 in e2
select v

é convertido emis translated into

( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )

Uma expressão de consulta com uma segunda from cláusula seguido por algo diferente de um select cláusula:A query expression with a second from clause followed by something other than a select clause:

from x1 in e1
from x2 in e2
...

é convertido emis translated into

from * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } )
...

Uma expressão de consulta com um let cláusulaA query expression with a let clause

from x in e
let y = f
...

é convertido emis translated into

from * in ( e ) . Select ( x => new { x , y = f } )
...

Uma expressão de consulta com um where cláusulaA query expression with a where clause

from x in e
where f
...

é convertido emis translated into

from x in ( e ) . Where ( x => f )
...

Uma expressão de consulta com um join cláusula sem uma into seguido por um select cláusulaA 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

é convertido emis translated into

( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => v )

Uma expressão de consulta com um join cláusula sem uma into seguido por algo diferente de um select cláusulaA 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
...

é convertido emis translated into

from * in ( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })
...

Uma expressão de consulta com um join cláusula com um into seguido por um select cláusulaA 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

é convertido emis translated into

( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => v )

Uma expressão de consulta com um join cláusula com um into seguido por algo diferente de um select cláusulaA 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
...

é convertido emis translated into

from * in ( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => new { x1 , g })
...

Uma expressão de consulta com um orderby cláusulaA query expression with an orderby clause

from x in e
orderby k1 , k2 , ..., kn
...

é convertido emis translated into

from x in ( e ) . 
OrderBy ( x => k1 ) . 
ThenBy ( x => k2 ) .
... .
ThenBy ( x => kn )
...

Se uma ordenação cláusula Especifica um descending indicador de direção, uma invocação de OrderByDescending ou ThenByDescending é produzido em vez disso.If an ordering clause specifies a descending direction indicator, an invocation of OrderByDescending or ThenByDescending is produced instead.

As traduções a seguir supõem que não há nenhum let, where, join ou orderby cláusulas e não mais do que aquele inicial from cláusula em cada expressão de consulta.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.

O exemploThe example

from c in customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total }

é convertido emis translated into

customers.
SelectMany(c => c.Orders,
     (c,o) => new { c.Name, o.OrderID, o.Total }
)

O exemploThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }

é convertido emis 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 }

a tradução final que éthe 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 })

onde x é um identificador gerado pelo compilador que de outra forma inacessíveis e invisível.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

O exemploThe example

from o in orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t }

é convertido emis 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 }

a tradução final que éthe 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 })

onde x é um identificador gerado pelo compilador que de outra forma inacessíveis e invisível.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

O exemploThe example

from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }

é convertido emis translated into

customers.Join(orders, c => c.CustomerID, o => o.CustomerID,
    (c, o) => new { c.Name, o.OrderDate, o.Total })

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

é convertido emis 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 }

a tradução final que éthe 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)

em que x e y são identificadores gerado pelo compilador que estariam invisíveis e inacessíveis.where x and y are compiler generated identifiers that are otherwise invisible and inaccessible.

O exemploThe example

from o in orders
orderby o.Customer.Name, o.Total descending
select o

tem a tradução finalhas the final translation

orders.
OrderBy(o => o.Customer.Name).
ThenByDescending(o => o.Total)

Cláusulas SELECTSelect clauses

Uma expressão de consulta do formulárioA query expression of the form

from x in e select v

é convertido emis translated into

( e ) . Select ( x => v )

exceto quando v é o identificador de x, a tradução é simplesmenteexcept when v is the identifier x, the translation is simply

( e )

Por exemploFor example

from c in customers.Where(c => c.City == "London")
select c

simplesmente é traduzido emis simply translated into

customers.Where(c => c.City == "London")

Cláusulas de GroupByGroupby clauses

Uma expressão de consulta do formulárioA query expression of the form

from x in e group v by k

é convertido emis translated into

( e ) . GroupBy ( x => k , x => v )

exceto quando v é o identificador de x, a tradução éexcept when v is the identifier x, the translation is

( e ) . GroupBy ( x => k )

O exemploThe example

from c in customers
group c.Name by c.Country

é convertido emis translated into

customers.
GroupBy(c => c.Country, c => c.Name)

Identificadores transparentesTransparent identifiers

Determinadas conversões de injetar as variáveis de intervalo com identificadores transparentes indicada por *.Certain translations inject range variables with transparent identifiers denoted by *. Identificadores transparentes não são um recurso de idioma apropriados; elas existem somente como uma etapa intermediária no processo de conversão de expressão de consulta.Transparent identifiers are not a proper language feature; they exist only as an intermediate step in the query expression translation process.

Quando uma conversão de consulta injeta um identificador transparente, ainda mais etapas de conversão propagam o identificador transparente para funções anônimas e inicializadores de objeto anônimos.When a query translation injects a transparent identifier, further translation steps propagate the transparent identifier into anonymous functions and anonymous object initializers. Nesses contextos, transparentes identificadores têm o seguinte comportamento:In those contexts, transparent identifiers have the following behavior:

  • Quando ocorre um identificador transparente como um parâmetro em uma função anônima, os membros do tipo anônimo associado são automaticamente no escopo no corpo da função anônima.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.
  • Quando um membro com um identificador transparente está no escopo, os membros desse membro estão no escopo também.When a member with a transparent identifier is in scope, the members of that member are in scope as well.
  • Quando ocorre um identificador transparente como um Declarador de membro de um inicializador de objeto anônimo, ele introduz um membro com um identificador transparente.When a transparent identifier occurs as a member declarator in an anonymous object initializer, it introduces a member with a transparent identifier.
  • As etapas de conversão descritas acima, sempre são introduzidos identificadores transparentes junto com os tipos anônimos, com a intenção de capturar várias variáveis de intervalo como membros de um único objeto.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. Uma implementação da linguagem c# tem permissão para usar um mecanismo diferente de tipos anônimos para agrupar diversas variáveis de intervalo.An implementation of C# is permitted to use a different mechanism than anonymous types to group together multiple range variables. Os exemplos de conversão a seguir pressupõem que tipos anônimos são usados e mostram como transparentes identificadores podem ser convertidos imediatamente.The following translation examples assume that anonymous types are used, and show how transparent identifiers can be translated away.

O exemploThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.Total }

é convertido emis translated into

from * in customers.
    SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.Total }

que é ainda mais convertidas emwhich is further translated into

customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(* => o.Total).
Select(* => new { c.Name, o.Total })

que, quando são apagados identificadores transparentes, é equivalente awhich, 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 })

onde x é um identificador gerado pelo compilador que de outra forma inacessíveis e invisível.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

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

é convertido emis 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 }

que é ainda mais reduzida parawhich 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 })

a tradução final que éthe 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 })

em que x, y, e z são identificadores gerado pelo compilador que estariam invisíveis e inacessíveis.where x, y, and z are compiler generated identifiers that are otherwise invisible and inaccessible.

O padrão de expressão de consultaThe query expression pattern

O padrão de expressão de consulta estabelece um padrão de métodos de tipos podem implementar para dar suporte a expressões de consulta.The Query expression pattern establishes a pattern of methods that types can implement to support query expressions. Como as expressões de consulta são traduzidas para invocações de método por meio de um mapeamento sintático, tipos têm flexibilidade considerável no modo como implementam o padrão de expressão de consulta.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. Por exemplo, os métodos do padrão podem ser implementados como métodos de instância ou como métodos de extensão porque os dois têm a mesma sintaxe de invocação e os métodos podem solicitar delegados ou árvores de expressão porque funções anônimas podem ser convertidas para ambos.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.

A forma recomendada de um tipo genérico C<T> que dá suporte ao padrão da expressão de consulta é mostrado abaixo.The recommended shape of a generic type C<T> that supports the query expression pattern is shown below. Um tipo genérico é usado para ilustrar as relações corretas entre tipos de parâmetro e resultado, mas é possível implementar o padrão para tipos não genéricos também.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; }
}

Os métodos acima usam os tipos de delegado genérico Func<T1,R> e Func<T1,T2,R>, mas pode igualmente bem ter usados outros tipos de árvore de delegado ou expressão com as mesmas relações nos tipos de parâmetro e resultado.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.

Observe a relação recomendada entre C<T> e O<T> que garante que o ThenBy e ThenByDescending métodos estão disponíveis somente no resultado de um 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. Observe também a forma recomendada de resultado de GroupBy – uma sequência de sequências, onde cada sequência interna tem mais Key propriedade.Also notice the recommended shape of the result of GroupBy -- a sequence of sequences, where each inner sequence has an additional Key property.

O System.Linq namespace fornece uma implementação do padrão de operador de consulta para qualquer tipo que implementa o System.Collections.Generic.IEnumerable<T> interface.The System.Linq namespace provides an implementation of the query operator pattern for any type that implements the System.Collections.Generic.IEnumerable<T> interface.

Operadores de atribuiçãoAssignment operators

Os operadores de atribuição atribui um novo valor para uma variável, uma propriedade, um evento ou um elemento do indexador.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
    ;

O operando esquerdo de uma atribuição deve ser uma expressão classificada como uma variável, um acesso de propriedade, um acesso de indexador ou um acesso de evento.The left operand of an assignment must be an expression classified as a variable, a property access, an indexer access, or an event access.

O = é chamado de operador de operador de atribuição simples.The = operator is called the simple assignment operator. Ele atribui o valor do operando à direita para o elemento de variável, propriedade ou indexador fornecido pelo operando à esquerda.It assigns the value of the right operand to the variable, property, or indexer element given by the left operand. O operando esquerdo do operador de atribuição simples pode não ser um acesso de evento (exceto conforme descrito em eventos semelhantes a campo).The left operand of the simple assignment operator may not be an event access (except as described in Field-like events). O operador de atribuição simples é descrito em atribuição simples.The simple assignment operator is described in Simple assignment.

Os operadores de atribuição que o = operador são chamados de operadores de atribuição composta.The assignment operators other than the = operator are called the compound assignment operators. Esses operadores de executam a operação indicada em dois operandos e, em seguida, atribua o valor resultante para o elemento de variável, propriedade ou indexador fornecido pelo operando à esquerda.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. Os operadores de atribuição composta são descritos em atribuição composta.The compound assignment operators are described in Compound assignment.

O += e -= são chamados de operadores com uma expressão de acesso de evento como o operando esquerdo a operadores de atribuição de evento.The += and -= operators with an event access expression as the left operand are called the event assignment operators. Nenhum outro operador de atribuição é válido com acesso de um evento que o operando esquerdo.No other assignment operator is valid with an event access as the left operand. Os operadores de atribuição de evento são descritos em atribuição de evento.The event assignment operators are described in Event assignment.

Os operadores de atribuição são associativos à direita, o que significa que as operações são agrupadas da direita para esquerda.The assignment operators are right-associative, meaning that operations are grouped from right to left. Por exemplo, uma expressão do formulário a = b = c é avaliada como a = (b = c).For example, an expression of the form a = b = c is evaluated as a = (b = c).

Atribuição simplesSimple assignment

O = operador é chamado de operador de atribuição simples.The = operator is called the simple assignment operator.

Se o operando esquerdo de uma atribuição simples tem o formato E.P ou E[Ei] onde E tem o tipo de tempo de compilação dynamic, em seguida, a atribuição é associada dinamicamente (vinculação dinâmica).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). Nesse caso é o tipo de tempo de compilação da expressão de atribuição dynamic, e a resolução descrita a seguir ocorrerá em tempo de execução com base no tipo de tempo de execução do 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.

Em uma atribuição simples, o operando direito deve ser uma expressão que é implicitamente conversível para o tipo do operando esquerdo.In a simple assignment, the right operand must be an expression that is implicitly convertible to the type of the left operand. A operação atribui o valor do operando à direita para o elemento de variável, propriedade ou indexador fornecido pelo operando à esquerda.The operation assigns the value of the right operand to the variable, property, or indexer element given by the left operand.

O resultado de uma expressão de atribuição simples é o valor atribuído ao operando esquerdo.The result of a simple assignment expression is the value assigned to the left operand. O resultado tem o mesmo tipo que o operando esquerdo e sempre é classificado como um valor.The result has the same type as the left operand and is always classified as a value.

Se o operando esquerdo é um acesso de propriedade ou indexador, propriedade ou indexador deve ter um set acessador.If the left operand is a property or indexer access, the property or indexer must have a set accessor. Se isso não for o caso, ocorre um erro em tempo de vinculação.If this is not the case, a binding-time error occurs.

O processamento de tempo de execução de uma atribuição simples do formulário x = y consiste as seguintes etapas:The run-time processing of a simple assignment of the form x = y consists of the following steps:

  • Se x é classificado como uma variável:If x is classified as a variable:
    • x é avaliado para produzir a variável.x is evaluated to produce the variable.
    • y é avaliado e, se necessário, convertido no tipo de x por meio de uma conversão implícita (conversões implícitas).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • Se a variável fornecida pelo x é um elemento de matriz de um reference_type, é realizada uma verificação de tempo de execução para garantir que o valor calculado para y é compatível com a instância de matriz da qual x é um elemento.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. A verificação for bem-sucedida se y está null, ou se uma conversão implícita de referência (conversões de referência implícita) existe do tipo real da instância referenciada por y ao tipo de elemento real de que a instância de matriz que contém 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. Caso contrário, uma System.ArrayTypeMismatchException será gerada.Otherwise, a System.ArrayTypeMismatchException is thrown.
    • O valor resultante da avaliação e a conversão de y é armazenado no local fornecido pela avaliação de x.The value resulting from the evaluation and conversion of y is stored into the location given by the evaluation of x.
  • Se x é classificado como um acesso de propriedade ou indexador:If x is classified as a property or indexer access:
    • A expressão de instância (se x não é static) e a lista de argumentos (se x é um indexador de acesso) associadas com x são avaliados, e os resultados são usados em subsequente set invocação do acessador.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 é avaliado e, se necessário, convertido no tipo de x por meio de uma conversão implícita (conversões implícitas).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • O set acessador da x é invocado com o valor calculado para y como seu value argumento.The set accessor of x is invoked with the value computed for y as its value argument.

As regras de variação conjunta de matriz (covariância de matriz) permite um valor de um tipo de matriz A[] seja uma referência a uma instância de um tipo de matriz B[], desde que existe uma conversão de referência implícita de B para 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. Devido a essas regras, a atribuição a um elemento de matriz de um reference_type requer uma verificação de tempo de execução para garantir que o valor que está sendo atribuído é compatível com a instância de matriz.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. No exemploIn the example

string[] sa = new string[10];
object[] oa = sa;

oa[0] = null;               // Ok
oa[1] = "Hello";            // Ok
oa[2] = new ArrayList();    // ArrayTypeMismatchException

faz com que a última atribuição de um System.ArrayTypeMismatchException ser lançada porque uma instância do ArrayList não podem ser armazenados em um elemento de um 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[].

Quando uma propriedade ou indexador declarado em uma struct_type é o destino de uma atribuição, a expressão de instância associado à propriedade ou o acesso ao indexador deve ser classificado como uma variável.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. Se a expressão de instância é classificada como um valor, ocorrerá um erro de tempo de associação.If the instance expression is classified as a value, a binding-time error occurs. Por causa da acesso de membro, a mesma regra também se aplica aos campos.Because of Member access, the same rule also applies to fields.

Dadas as declarações: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; }
    }
}

No exemploin 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;

as atribuições para p.X, p.Y, r.A, e r.B são permitidas porque p e r são variáveis.the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. No entanto, no exemploHowever, in the example

Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;

as atribuições são todos inválidas, desde r.A e r.B não são variáveis.the assignments are all invalid, since r.A and r.B are not variables.

Atribuição compostaCompound assignment

Se o operando esquerdo de uma atribuição composta tem o formato E.P ou E[Ei] onde E tem o tipo de tempo de compilação dynamic, em seguida, a atribuição é associada dinamicamente (vinculação dinâmica).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). Nesse caso é o tipo de tempo de compilação da expressão de atribuição dynamic, e a resolução descrita a seguir ocorrerá em tempo de execução com base no tipo de tempo de execução do 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.

Uma operação do formulário x op= y é processado por meio da aplicação de resolução de sobrecarga de operador binário (resolução de sobrecarga de operador binário) como se a operação foi escrita 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. Em seguida,Then,

  • Se o tipo de retorno do operador selecionado é implicitamente conversível para o tipo de x, a operação é avaliada como x = x op y, exceto que x é avaliada apenas uma vez.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.
  • Caso contrário, se o operador selecionado é um operador predefinido, se o tipo de retorno do operador selecionado é explicitamente convertido no tipo de xe se y é implicitamente conversível para o tipo de x ou o operador é um operador, de deslocamento, em seguida, a operação é avaliada como x = (T)(x op y), onde T é o tipo de x, exceto que x é avaliada apenas uma vez.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.
  • Caso contrário, a atribuição composta é inválida e ocorre um erro em tempo de vinculação.Otherwise, the compound assignment is invalid, and a binding-time error occurs.

O termo "avaliado apenas uma vez" significa que, na avaliação de x op y, os resultados de todas as expressões de constituintes x são temporariamente salvos e reutilizados, em seguida, ao executar a atribuição ao x.The term "evaluated only once" means that in the evaluation of x op y, the results of any constituent expressions of x are temporarily saved and then reused when performing the assignment to x. Por exemplo, na atribuição A()[B()] += C(), onde A é um método que retorna int[], e B e C são métodos que retornam int, os métodos são chamados apenas uma vez, na ordem A, B, C.For example, in the assignment A()[B()] += C(), where A is a method returning int[], and B and C are methods returning int, the methods are invoked only once, in the order A, B, C.

Quando o operando esquerdo de uma atribuição composta é um acesso de propriedade ou o acesso do indexador, propriedade ou indexador deve ter uma get acessador e um set acessador.When the left operand of a compound assignment is a property access or indexer access, the property or indexer must have both a get accessor and a set accessor. Se isso não for o caso, ocorre um erro em tempo de vinculação.If this is not the case, a binding-time error occurs.

A segunda regra acima permite x op= y a ser avaliada como x = (T)(x op y) em determinados contextos.The second rule above permits x op= y to be evaluated as x = (T)(x op y) in certain contexts. A regra existe, de modo que a operadores predefinidos podem ser usados como operadores compostos quando o operando esquerdo for do tipo sbyte, byte, short, ushort, ou char.The rule exists such that the predefined operators can be used as compound operators when the left operand is of type sbyte, byte, short, ushort, or char. Até mesmo quando ambos os argumentos forem de um desses tipos, os operadores predefinidos produzem um resultado do tipo int, conforme descrito em promoções numéricas binárias.Even when both arguments are of one of those types, the predefined operators produce a result of type int, as described in Binary numeric promotions. Portanto, sem uma conversão não seria possível atribuir o resultado ao operando esquerdo.Thus, without a cast it would not be possible to assign the result to the left operand.

O efeito intuitivo da regra para operadores predefinidos é simplesmente que x op= y é permitido se os dois dos x op y e x = y são permitidos.The intuitive effect of the rule for predefined operators is simply that x op= y is permitted if both of x op y and x = y are permitted. No exemploIn the example

byte b = 0;
char ch = '\0';
int i = 0;

b += 1;             // Ok
b += 1000;          // Error, b = 1000 not permitted
b += i;             // Error, b = i not permitted
b += (byte)i;       // Ok

ch += 1;            // Error, ch = 1 not permitted
ch += (char)1;      // Ok

o motivo intuitivo para cada erro é que uma simples atribuição correspondente também seria um erro.the intuitive reason for each error is that a corresponding simple assignment would also have been an error.

Isso também significa que dar suporte a operações de atribuição composta eliminada operações.This also means that compound assignment operations support lifted operations. No exemploIn the example

int? i = 0;
i += 1;             // Ok

o operador elevado +(int?,int?) é usado.the lifted operator +(int?,int?) is used.

Atribuição de eventoEvent assignment

Se o operando esquerdo de uma += ou -= operador é classificado como um acesso de evento e, em seguida, a expressão é avaliada da seguinte maneira:If the left operand of a += or -= operator is classified as an event access, then the expression is evaluated as follows:

  • A expressão de instância, se houver, do acesso do evento é avaliada.The instance expression, if any, of the event access is evaluated.
  • O operando direito dos += ou -= operador é avaliado e, se necessário, convertido para o tipo do operando à esquerda por meio de uma conversão implícita (conversões implícitas).The right operand of the += or -= operator is evaluated, and, if required, converted to the type of the left operand through an implicit conversion (Implicit conversions).
  • Um acessador de evento do evento é invocado, com a lista de argumentos que consiste do operando à direita, após a avaliação e, se necessário, conversão.An event accessor of the event is invoked, with argument list consisting of the right operand, after evaluation and, if necessary, conversion. Se o operador foi +=, o add acessador é invocado; se o operador foi -=, o remove acessador é invocado.If the operator was +=, the add accessor is invoked; if the operator was -=, the remove accessor is invoked.

Uma expressão de atribuição de evento não produz um valor.An event assignment expression does not yield a value. Portanto, uma expressão de atribuição de evento é válida somente no contexto de um statement_expression (instruções de expressão).Thus, an event assignment expression is valid only in the context of a statement_expression (Expression statements).

ExpressãoExpression

Uma expressão é um non_assignment_expression ou uma atribuição.An expression is either a non_assignment_expression or an assignment.

expression
    : non_assignment_expression
    | assignment
    ;

non_assignment_expression
    : conditional_expression
    | lambda_expression
    | query_expression
    ;

Expressões constantesConstant expressions

Um constant_expression é uma expressão que pode ser completamente avaliada em tempo de compilação.A constant_expression is an expression that can be fully evaluated at compile-time.

constant_expression
    : expression
    ;

Uma expressão constante deve ser o null literal ou um valor com um dos seguintes tipos: sbyte, byte, short, ushort, int, uint, long, ulong, char , float, double, decimal, bool, object, string, ou qualquer tipo de enumeração.A constant expression must be the null literal or a value with one of the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, object, string, or any enumeration type. Somente as seguintes construções são permitidas em expressões constantes:Only the following constructs are permitted in constant expressions:

  • Literais (incluindo o null literal).Literals (including the null literal).
  • As referências a const membros de tipos de classe e struct.References to const members of class and struct types.
  • Referências aos membros de tipos de enumeração.References to members of enumeration types.
  • As referências a const parâmetros ou variáveis locaisReferences to const parameters or local variables
  • Entre parênteses subexpressões, que são as próprias expressões de constante.Parenthesized sub-expressions, which are themselves constant expressions.
  • Expressões de conversão, fornecidas o tipo de destino é um dos tipos listados acima.Cast expressions, provided the target type is one of the types listed above.
  • checked e unchecked expressõeschecked and unchecked expressions
  • Expressões de valor padrãoDefault value expressions
  • Expressões NameofNameof expressions
  • Predefinido +, -, !, e ~ operadores unários.The predefined +, -, !, and ~ unary operators.
  • Predefinido +, -, *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, e >= operadores binários, desde que cada operando seja de um tipo listado acima.The predefined +, -, *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators, provided each operand is of a type listed above.
  • O ?: operador condicional.The ?: conditional operator.

As conversões a seguir são permitidas em expressões constantes:The following conversions are permitted in constant expressions:

  • Conversões de identidadeIdentity conversions
  • Conversões numéricasNumeric conversions
  • Conversões de enumeraçãoEnumeration conversions
  • Conversões de expressão de constanteConstant expression conversions
  • Conversões de referência implícita e explícita, fornecidas a fonte das conversões é uma expressão constante que é avaliada como o valor nulo.Implicit and explicit reference conversions, provided that the source of the conversions is a constant expression that evaluates to the null value.

Outras conversões, incluindo a conversão boxing, conversão unboxing e referência conversões implícitas de valores não nulos não são permitidas em expressões de constante.Other conversions including boxing, unboxing and implicit reference conversions of non-null values are not permitted in constant expressions. Por exemplo:For example:

class C {
    const object i = 5;         // error: boxing conversion not permitted
    const object str = "hello"; // error: implicit reference conversion
}

a inicialização de i é um erro, pois uma conversão boxing é necessária.the initialization of i is an error because a boxing conversion is required. A inicialização de str é um erro porque uma conversão de referência implícita de um valor não nulo é necessária.The initialization of str is an error because an implicit reference conversion from a non-null value is required.

Sempre que uma expressão cumpre os requisitos listados acima, a expressão é avaliada em tempo de compilação.Whenever an expression fulfills the requirements listed above, the expression is evaluated at compile-time. Isso é verdadeiro mesmo se a expressão for uma subexpressão de uma expressão maior que contém construções não constante.This is true even if the expression is a sub-expression of a larger expression that contains non-constant constructs.

A avaliação do tempo de compilação de expressões de constante usa as mesmas regras como tempo de execução de avaliação de expressões não constantes, exceto que, em que a avaliação de tempo de execução teria sido gerada uma exceção, a avaliação do tempo de compilação faz com que ocorra um erro de tempo de compilação.