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 de operandos e operadores e o significado de 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 uma das 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 em 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 as), ois
operador (o operador is) ou otypeof
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 theas
operator (The as operator), theis
operator (The is operator), or thetypeof
operator (The typeof operator). Em qualquer outro contexto, uma expressão classificada como um tipo 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étodos, 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étodos 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 se torna a instância representada por
this
(esse acesso).When an instance method is invoked, the result of evaluating the instance expression becomes the instance represented bythis
(This access). Um grupo de métodos é permitido em um invocation_expression (expressões de invocação), um delegate_creation_expression (expressões de criação de delegado) e como o lado esquerdo de um operador is e pode ser convertido implicitamente em um tipo de delegado compatível (conversões de grupo de métodos).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 em 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 em 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 convertida implicitamente em um tipo de representante ou tipo de árvore de expressão compatível.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. Cada 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
set
bloco ou) de um acesso de propriedade de instância é invocado, o resultado da avaliação da expressão de instância se torna a instância representada porthis
(esse acesso).When an accessor (theget
orset
block) of an instance property access is invoked, the result of evaluating the instance expression becomes the instance represented bythis
(This access). - Um acesso de evento.An event access. Cada acesso de 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, um acesso de 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 dos
+=
-=
operadores e (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. - Um acesso ao indexador.An indexer access. Cada acesso ao 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, um acesso ao 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
set
bloco ou) de um acesso do indexador é invocado, o resultado da avaliação da expressão de instância se torna a instância representada pelothis
(esse acesso) e o resultado da avaliação da lista de argumentos se torna a lista de parâmetros da invocação.When an accessor (theget
orset
block) of an indexer access is invoked, the result of evaluating the instance expression becomes the instance represented bythis
(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 de
void
.This occurs when the expression is an invocation of a method with a return type ofvoid
. Uma expressão classificada como Nothing só é válida no contexto de uma 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, grupo de métodos ou acesso de 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ó são permitidas 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 de indexador é sempre reclassificado como um valor executando 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 específico é determinado pelo contexto da propriedade ou do acesso do indexador: se o acesso for o destino de uma atribuição, o acessador set será invocado 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 é invocado para obter o valor atual (valores de 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 denotasse um 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 em 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, do indexador ou da variável é substituído implicitamente: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 atualmente armazenado 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 definitivamente atribuída (atribuição definitiva) antes que seu valor possa 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 à 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 nenhum acessador get, ocorrerá um erro em tempo de compilação.If the property has no get accessor, a compile-time error occurs. Caso contrário, uma invocação de membrode função (verificação de tempo de compilação da resolução dinâmica de sobrecarga) será executada e o resultado da invocação se tornará o valor da expressão de acesso à 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 nenhum acessador get, ocorrerá um erro em tempo de compilação.If the indexer has no get accessor, a compile-time error occurs. Caso contrário, uma invocação de membrode função (verificação de tempo de compilação da resolução dinâmica de sobrecarga) é executada com a lista de argumentos associada à expressão de acesso do indexador e o resultado da invocação se torna 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 conhecido como 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 de receptor e argumentos.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 geralmente é determinado em tempo de compilação, com base no tipo de tempo de compilação de 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 será detectado e relatado pelo compilador.Likewise, if an expression contains an error, the error is detected and reported by the compiler. Essa abordagem é conhecida como associação estática.This approach is known as static binding.
No entanto, se uma expressão for uma expressão dinâmica (ou seja, tiver o tipo dynamic
), isso indicará que qualquer associação na qual ela participa deve ser baseada em seu tipo de tempo de execução (ou seja, o tipo real do objeto que ele denota em tempo de execução) em vez do tipo que ele tem em 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 de tal operação é, portanto, adiada até o momento em que a operação deve ser executada 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 associaçã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 serã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 sujeitas à associação:The following operations in C# are subject to binding:
- Acesso de membro:
e.M
Member 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 ao elemento:
e[e1, ..., eN]
Element access:e[e1, ..., eN]
- Criação de objeto:
new C(e1, ..., eN)
Object creation:new C(e1, ..., eN)
- Operadores unários sobrecarregados:,,,,,,
+
-
!
~
++
--
true
,false
Overloaded unary operators:+
,-
,!
,~
,++
,--
,true
,false
- Operadores binários sobrecarregados:,,,,,,
+
-
*
/
%
&
&&
,|
,||
,??
,,,,^
,,<<
>>
==
!=
>
,<
,>=
,<=
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 envolvidas, o C# assume como padrão a associaçã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 é 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
A associação estática ocorre no tempo de compilação, enquanto a associaçã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 Associação de tempo refere- se ao tempo de compilação ou tempo de execução, dependendo de quando a associação ocorre.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 vinculaçã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 de 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. Portanto, o tempo de associação é de tempo de compilação.Thus, the binding-time is compile-time.
A terceira chamada é vinculada dinamicamente: a sobrecarga de Console.WriteLine
é escolhida com base no tipo de tempo de execução de 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 é tempo de execução.Thus, the binding-time for the third call is run-time.
Associação dinâmicaDynamic binding
A finalidade da vinculação dinâmica é permitir que programas em C# interajam com objetos dinâmicos, ou seja, objetos que não seguem as regras normais do sistema de tipos 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 que são configurados programaticamente para implementar sua própria semântica de ligaçã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 sua própria semântica é a implementação definida.The mechanism by which a dynamic object implements its own semantics is implementation defined. Uma determinada interface – novamente definida--é implementada por objetos dinâmicos para sinalizar para o tempo de execução do C# 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. Portanto, sempre que as operações em um objeto dinâmico forem vinculadas dinamicamente, sua própria semântica de ligação, em vez das do 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.
Embora a finalidade da vinculação dinâmica seja permitir a interoperação com objetos dinâmicos, o C# permite a vinculação dinâmica em todos os objetos, sejam eles 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, pois os resultados das operações neles não podem ser objetos dinâmicos, mas ainda são 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. Além disso, a ligação dinâmica pode ajudar a eliminar códigos baseados em reflexão propensos a erros, mesmo quando nenhum objeto envolvido é um objeto dinâmico.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 construção no idioma exatamente quando a vinculação dinâmica é aplicada, qual é a verificação de tempo de compilação – se houver, se houver, e qual será o resultado de tempo de compilação e a classificação de expressã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 receptor, um argumento, um índice ou um operando) é sempre considerado 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 é vinculada dinamicamente, 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 de tipo de tempo de compilação
dynamic
é considerada como tendo o tipo do valor real que a expressão avalia em tempo de execuçãoA constituent expression of compile-time typedynamic
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 é considerado como tendo o tipo ao qual o parâmetro de tipo está 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 será considerada com seu tipo de tempo de compilação.Otherwise the constituent expression is considered to have its compile-time type.
OperadoresOperators
As expressões são construídas de 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 usam a notação de prefixo (como
--x
) ou a notação de sufixo (comox++
).The unary operators take one operand and use either prefix notation (such as--x
) or postfix notation (such asx++
). - Operadores binários.Binary operators. Os operadores binários usam dois operandos e todos usam notação de infixo (como
x + y
).The binary operators take two operands and all use infix notation (such asx + y
). - Operador ternário.Ternary operator. Há apenas um operador ternário,
?:
,, 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 dos operadores em uma expressão é determinada pela precedência _ e _ Associação dos operadores (precedência de operador e Associação).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, no F(i) + G(i++) * H(i)
, o método F
é chamado usando o valor antigo de i
, então G
o método é chamado com o valor antigo de i
e, finalmente, H
o método é 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 é separado de e não relacionado à precedência de operador.This is separate from and unrelated to operator precedence.
Determinados operadores podem ser sobrecarregados.Certain operators can be overloaded. A sobrecarga de operador permite que as implementações de operador definidas pelo usuário sejam especificadas para operações em que um ou ambos os operandos são de uma classe definida pelo usuário ou tipo struct (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 contém 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
é avaliada como x + (y * z)
porque o operador *
tem precedência maior do que o operador binário +
.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 da sua produção de gramática associada.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_expression s separados por +
-
operadores or, dando, assim, os operadores +
e a -
precedência mais baixa do que os *
/
operadores, e %
.For example, an additive_expression consists of a sequence of multiplicative_expression s separated by +
or -
operators, thus giving the +
and -
operators lower precedence than the *
, /
, and %
operators.
A tabela a seguir resume todos os operadores em ordem de precedência do mais alto para o mais baixo:The following table summarizes all operators in order of precedence from highest to lowest:
SeçãoSection | CategoriaCategory | OperadoresOperators |
---|---|---|
Expressões primáriasPrimary expressions | PrimárioPrimary | x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate x.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 | AditivaAdditive | + - + - |
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 | IgualitárioEquality | == != == != |
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ônimasAssignment 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, o que significa que as 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 (
?:
) são associativos à direita, o que significa que as operações são executadas da direita para a 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 comox = (y = z)
.For example,x = y = z
is evaluated asx = (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 implementações predefinidas que estão automaticamente disponíveis em qualquer expressão.All unary and binary operators have predefined implementations that are automatically available in any expression. Além das implementações predefinidas, as implementações definidas pelo usuário podem ser introduzidas com a inclusão de 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 definidas pelo usuário sempre têm precedência sobre implementações de operador predefinidas: somente quando não houver nenhuma implementação de operador definida pelo usuário aplicável as implementações de operador predefinidas serão consideradas, conforme descrito em resolução de sobrecarga de operador unário e resolução de sobrecarga de operador binário.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.
Os operadores unários sobrecarregados são:The overloadable unary operators are:
+ - ! ~ ++ -- true false
Embora true
e false
não sejam usados explicitamente em expressões (e, portanto, não sejam incluídos na tabela de precedência em precedência de operador e Associação), eles são considerados operadores porque são invocados em vários contextos de expressão: expressões boolianas (expressões booleanas) e expressões que envolvem o condicional (operador condicional) e operadores lógicos condicionais (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).
Os operadores binários sobrecarregados 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, a invocação de método ou os operadores,,,,,,,,,,, =
&&
||
??
?:
=>
checked
unchecked
new
typeof
default
as
e is
.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 mais detalhadamente na atribuição composta.This is described further in Compound assignment. Observe que o próprio operador de atribuição ( =
) não pode ser sobrecarregado.Note that the assignment operator itself (=
) cannot be overloaded. Uma atribuição sempre executa uma cópia de bits simples de um valor em uma variável.An assignment always performs a simple bit-wise copy of a value into a variable.
As operações de conversão, como (T)x
, são sobrecarregadas 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).
O acesso ao elemento, como a[x]
, não é considerado um operador sobrecarregado.Element access, such as a[x]
, is not considered an overloadable operator. Em vez disso, há suporte para a indexação definida pelo usuário por meio de indexadores (indexadores).Instead, user-defined indexing is supported through indexers (Indexers).
Em expressões, os operadores são referenciados usando a notação de operador e, em declarações, os 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 as notações de operador e funcional para operadores unários e binários.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 sobrecarregado.In the first entry, op denotes any overloadable unary prefix operator. Na segunda entrada, op denota o sufixo e os operadores unários ++
--
.In the second entry, op denotes the unary postfix ++
and --
operators. Na terceira entrada, op denota qualquer operador binário sobrecarregado.In the third entry, op denotes any overloadable binary operator.
Notação de operadorOperator notation | Notação funcionalFunctional notation |
---|---|
op x |
operator op(x) |
x op |
operator op(x) |
x op y |
operator op(x,y) |
As declarações de operador definidas pelo usuário sempre exigem que pelo menos um dos parâmetros seja 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 que um operador definido pelo usuário tenha a mesma assinatura que um operador predefinido.Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.
As declarações do operador definidas pelo usuário não podem modificar a sintaxe, a precedência ou a associação de um 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 especificado em precedência de operador e Associação, e é sempre associativo à 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 que um operador definido pelo usuário execute qualquer computação, as implementações que produzem resultados diferentes daqueles que são intuitivos esperados são altamente desencorajadas.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 do operator ==
deve comparar os dois operandos para igualdade e retornar um bool
resultado apropriado.For example, an implementation of operator ==
should compare the two operands for equality and return an appropriate bool
result.
As descrições de operadores individuais em expressões primárias por meio de operadores lógicos condicionais especificam as implementações predefinidas dos operadores e quaisquer regras adicionais que se aplicam a 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. As descrições usam os termos unários de sobrecarga de operador resolução _, _resolução de sobrecarga de operador binário*_ e _ promoção numérica *, definições das quais são encontradas 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
, em que op
é um operador unário sobrecarregado e x
é uma expressão do tipo X
, é processada 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 candidatos definidos pelo usuário fornecido pelo
X
para a operaçãooperator op(x)
é determinado usando as regras de operadores definidos pelo usuário candidatos.The set of candidate user-defined operators provided byX
for the operationoperator op(x)
is determined using the rules of Candidate user-defined operators. - Se o conjunto de operadores candidatos definidos pelo usuário não estiver vazio, isso se tornará o conjunto de operadores candidatos 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, as implementações unários predefinidas
operator op
, incluindo suas formas levantadas, se tornarão o conjunto de operadores candidatos para a operação.Otherwise, the predefined unaryoperator 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 da resolução de sobrecarga são aplicadas ao conjunto de operadores candidatos para selecionar o melhor operador em relação à lista de argumentos
(x)
, e esse operador se torna o resultado do processo de resolução de sobrecarga.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 falhar ao 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
, em que op
é um operador binário sobrecarregado, x
é uma expressão do tipo X
e y
é uma expressão do tipo Y
, é processada 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 candidatos definidos pelo usuário fornecido pelo
X
eY
para a operaçãooperator op(x,y)
é determinado.The set of candidate user-defined operators provided byX
andY
for the operationoperator op(x,y)
is determined. O conjunto consiste na União dos operadores candidatos fornecidos peloX
e nos operadores candidatos fornecidos peloY
, cada um determinado usando as regras de operadores definidos pelo usuário candidatos.The set consists of the union of the candidate operators provided byX
and the candidate operators provided byY
, each determined using the rules of Candidate user-defined operators. SeX
eY
forem do mesmo tipo, ou seX
eY
forem derivados de um tipo base comum, os operadores de candidato compartilhados só ocorrerão no conjunto combinado uma vez.IfX
andY
are the same type, or ifX
andY
are derived from a common base type, then shared candidate operators only occur in the combined set once. - Se o conjunto de operadores candidatos definidos pelo usuário não estiver vazio, isso se tornará o conjunto de operadores candidatos 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, as implementações binárias predefinidas
operator op
, incluindo seus formulários levantados, se tornarão o conjunto de operadores candidatos para a operação.Otherwise, the predefined binaryoperator 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 de 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 operadores enum e delegate predefinidos, os únicos operadores considerados são aqueles definidos por um tipo de enumeração ou de 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 da resolução de sobrecarga são aplicadas ao conjunto de operadores candidatos para selecionar o melhor operador em relação à lista de argumentos
(x,y)
, e esse operador se torna o resultado do processo de resolução de sobrecarga.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 falhar ao 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 candidatosCandidate user-defined operators
Dado um tipo T
e uma operação operator op(A)
, em que op
é um operador que é sobrecarregado e A
é uma lista de argumentos, o conjunto de operadores candidatos definidos pelo usuário fornecido pelo for T
operator op(A)
é determinado 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:
- Determine o tipo
T0
.Determine the typeT0
. SeT
for um tipo anulável,T0
será seu tipo subjacente; caso contrário,T0
será igual aT
.IfT
is a nullable type,T0
is its underlying type, otherwiseT0
is equal toT
. - Para todas as
operator op
declarações emT0
e todas as formas compostas desses operadores, se pelo menos um operador for aplicável (membro de função aplicável) em relação à lista de argumentosA
, o conjunto de operadores candidatos consistirá em todos esses operadores aplicáveis noT0
.For alloperator op
declarations inT0
and all lifted forms of such operators, if at least one operator is applicable (Applicable function member) with respect to the argument listA
, then the set of candidate operators consists of all such applicable operators inT0
. - Caso contrário, se
T0
forobject
, o conjunto de operadores candidatos estará vazio.Otherwise, ifT0
isobject
, the set of candidate operators is empty. - Caso contrário, o conjunto de operadores candidatos fornecidos pelo
T0
é o conjunto de operadores candidatos fornecidos pela classe base direta deT0
, ou a classe base efetiva deT0
IfT0
é um parâmetro de tipo.Otherwise, the set of candidate operators provided byT0
is the set of candidate operators provided by the direct base class ofT0
, or the effective base class ofT0
ifT0
is a type parameter.
Promoções numéricasNumeric promotions
A promoção numérica consiste em executar automaticamente determinadas conversões implícitas dos operandos dos operadores numéricos unários e binários predefinidos.Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. A promoção numérica não é um mecanismo distinto, mas sim um efeito de aplicar a resolução de sobrecarga aos operadores predefinidos.Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. A promoção numérica especificamente não afeta a avaliação de operadores definidos pelo usuário, embora os operadores definidos pelo usuário possam ser implementados para exibir 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 exemplo de promoção numérica, considere as implementações predefinidas do *
operador binário: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 os quais conversões implícitas existem nos 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
, em que b
é um byte
e s
é um short
, a resolução de sobrecarga seleciona operator *(int,int)
como o melhor operador.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. Assim, 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
, em que i
é um int
e d
é um double
, a resolução de sobrecarga seleciona operator *(double,double)
como o melhor operador.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 numéricas unáriosUnary numeric promotions
A promoção numérica unário ocorre para os operandos dos operadores predefinidos +
, -
e ~
unários.Unary numeric promotion occurs for the operands of the predefined +
, -
, and ~
unary operators. A promoção numérica unário consiste simplesmente em converter operandos do tipo sbyte
,, byte
short
, ushort
ou char
para o tipo 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, a promoção numérica unário converte os operandos do tipo uint
para o tipo 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
A promoção numérica binária ocorre para os operandos dos operadores predefinidos,,,,,,,,,,, +
-
*
/
%
&
|
^
==
!=
>
<
, >=
e <=
binários.Binary numeric promotion occurs for the operands of the predefined +
, -
, *
, /
, %
, &
, |
, ^
, ==
, !=
, >
, <
, >=
, and <=
binary operators. A promoção numérica binária converte implicitamente os dois operandos em um tipo comum que, no caso dos operadores não relacionais, também se torna 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. A promoção numérica binária consiste na aplicação das seguintes regras, na ordem em que 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 em tipodecimal
ou um erro de tempo de ligação ocorrerá se o outro operando for do tipofloat
oudouble
.If either operand is of typedecimal
, the other operand is converted to typedecimal
, or a binding-time error occurs if the other operand is of typefloat
ordouble
. - Caso contrário, se qualquer operando for do tipo
double
, o outro operando será convertido em tipodouble
.Otherwise, if either operand is of typedouble
, the other operand is converted to typedouble
. - Caso contrário, se qualquer operando for do tipo
float
, o outro operando será convertido em tipofloat
.Otherwise, if either operand is of typefloat
, the other operand is converted to typefloat
. - Caso contrário, se qualquer operando for do tipo
ulong
, o outro operando será convertido em tipoulong
, ou um erro de tempo de ligação ocorrerá se o outro operando for do tiposbyte
,short
,int
oulong
.Otherwise, if either operand is of typeulong
, the other operand is converted to typeulong
, or a binding-time error occurs if the other operand is of typesbyte
,short
,int
, orlong
. - Caso contrário, se qualquer operando for do tipo
long
, o outro operando será convertido em tipolong
.Otherwise, if either operand is of typelong
, the other operand is converted to typelong
. - Caso contrário, se qualquer operando for do tipo
uint
e o outro operando for do tiposbyte
,short
ouint
, ambos os operandos serão convertidos para o tipolong
.Otherwise, if either operand is of typeuint
and the other operand is of typesbyte
,short
, orint
, both operands are converted to typelong
. - Caso contrário, se qualquer operando for do tipo
uint
, o outro operando será convertido em tipouint
.Otherwise, if either operand is of typeuint
, the other operand is converted to typeuint
. - Caso contrário, ambos os operandos serão convertidos para o tipo
int
.Otherwise, both operands are converted to typeint
.
Observe que a primeira regra não permite qualquer operação que misture o decimal
tipo com os double
tipos e float
.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á conversões implícitas entre o decimal
tipo e os double
tipos e float
.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 seja do tipo ulong
quando o outro operando é de um tipo integral assinado.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 não existe nenhum tipo integral que possa representar o intervalo completo ulong
, bem como os tipos integrais assinados.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 seja 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 um decimal
não pode ser multiplicado por um double
.a binding-time error occurs because a decimal
cannot be multiplied by a double
. O erro é resolvido convertendo explicitamente o segundo operando para 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 levantadosLifted operators
Operadores levantados permitem operadores predefinidos e definidos pelo usuário que operam em tipos de valores não anuláveis para também serem usados com formulários anuláveis 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. Os operadores levantados são construídos a partir de operadores predefinidos e definidos pelo usuário que atendem a determinados requisitos, conforme descrito no seguinte: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
+ ++ - -- ! ~
uma forma levantada de um operador existirá se o operando e os tipos de resultado forem tipos de valor não anuláveis.a lifted form of an operator exists if the operand and result types are both non-nullable value types. O formulário levantado é construído adicionando um único
?
modificador ao operando e tipos de resultado.The lifted form is constructed by adding a single?
modifier to the operand and result types. O operador levantado 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 levantado desencapsula 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 uma forma levantada de um operador se os tipos de operando e de resultado são todos os tipos de valor não anuláveis.a lifted form of an operator exists if the operand and result types are all non-nullable value types. O formulário levantado é construído adicionando um único
?
modificador a cada operando e tipo de resultado.The lifted form is constructed by adding a single?
modifier to each operand and result type. O operador levantado produz um valor nulo se um ou ambos os operandos forem nulos (uma exceção sendo os&
|
operadores e dobool?
tipo, conforme descrito em operadores lógicos boolianos).The lifted operator produces a null value if one or both operands are null (an exception being the&
and|
operators of thebool?
type, as described in Boolean logical operators). Caso contrário, o operador levantado desencapsula 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
== !=
uma forma levantada de um operador existe se os tipos de operando forem tipos de valor não anuláveis e se o tipo de resultado for
bool
.a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type isbool
. O formulário levantado é construído adicionando um único?
modificador a cada tipo de operando.The lifted form is constructed by adding a single?
modifier to each operand type. O operador levantado considera dois valores nulos iguais e um valor nulo é diferente de 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 levantado desencapsulará os operandos e aplicará o operador subjacente para produzir obool
resultado.If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce thebool
result.Para os operadores relacionaisFor the relational operators
< > <= >=
uma forma levantada de um operador existe se os tipos de operando forem tipos de valor não anuláveis e se o tipo de resultado for
bool
.a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type isbool
. O formulário levantado é construído adicionando um único?
modificador a cada tipo de operando.The lifted form is constructed by adding a single?
modifier to each operand type. O operador levantado produz o valorfalse
se um ou ambos os operandos forem nulos.The lifted operator produces the valuefalse
if one or both operands are null. Caso contrário, o operador levantado desencapsula os operandos e aplica o operador subjacente para produzir obool
resultado.Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce thebool
result.
Pesquisa de membrosMember 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 um Simple_name (nomes simples) ou uma member_access (acesso de membro) em uma 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 ocorrer como o primary_expression de um invocation_expression (invocações de método), o membro será chamado de chamada.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 for um método ou evento, ou se for uma constante, campo ou propriedade de um tipo delegado (delegados) ou do tipo dynamic
(o tipo dinâmico), o membro será dito como invocável.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.
A pesquisa de membros considera não apenas o nome de um membro, mas também o número de parâmetros de tipo que o membro tem e se o membro está 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 membros, os métodos genéricos e os tipos genéricos aninhados têm o número de parâmetros de tipo indicados 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 membro de um nome N
com K
parâmetros de tipo em um tipo T
é processada 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 namedN
is determined:- Se
T
for um parâmetro de tipo, o conjunto será a União dos conjuntos de membros acessíveis nomeadosN
em cada um dos tipos especificados como uma restrição primária ou restrição secundária (restrições de parâmetro de tipo) paraT
, juntamente com o conjunto de membros acessíveis nomeadosN
emobject
.IfT
is a type parameter, then the set is the union of the sets of accessible members namedN
in each of the types specified as a primary constraint or secondary constraint (Type parameter constraints) forT
, along with the set of accessible members namedN
inobject
. - Caso contrário, o conjunto consiste em todos os membros (acesso de membro) acessíveis chamados
N
noT
, incluindo membros herdados e os membros acessíveis chamadosN
emobject
.Otherwise, the set consists of all accessible (Member access) members namedN
inT
, including inherited members and the accessible members namedN
inobject
. SeT
for um tipo construído, o conjunto de membros será obtido pela substituição de argumentos de tipo, conforme descrito em membros de tipos construídos.IfT
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 umoverride
modificador são excluídos do conjunto.Members that include anoverride
modifier are excluded from the set.
- Se
- Em seguida, se
K
for zero, todos os tipos aninhados cujas declarações incluem parâmetros de tipo serão removidos.Next, ifK
is zero, all nested types whose declarations include type parameters are removed. SeK
não for zero, todos os membros com um número diferente de parâmetros de tipo serão removidos.IfK
is not zero, all members with a different number of type parameters are removed. Observe que quandoK
é zero, os métodos com parâmetros de tipo não são removidos, pois o processo de inferência de tipos (inferência de tipos) pode ser capaz de inferir os argumentos de tipo.Note that whenK
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 for invocado, todos os membros não invocáveis serã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, em queS
é o tipo no qual o membroM
é declarado, as regras a seguir são aplicadas:For every memberS.M
in the set, whereS
is the type in which the memberM
is declared, the following rules are applied:- Se
M
for uma constante, campo, propriedade, evento ou membro de enumeração, todos os membros declarados em um tipo base deS
serão removidos do conjunto.IfM
is a constant, field, property, event, or enumeration member, then all members declared in a base type ofS
are removed from the set. - Se
M
for uma declaração de tipo, todos os não tipos declarados em um tipo base deS
serão removidos do conjunto, e todas as declarações de tipo com o mesmo número de parâmetros de tipo, conformeM
declarado em um tipo base de,S
serão removidas do conjunto.IfM
is a type declaration, then all non-types declared in a base type ofS
are removed from the set, and all type declarations with the same number of type parameters asM
declared in a base type ofS
are removed from the set. - Se
M
for um método, todos os membros não-método declarados em um tipo base deS
serão removidos do conjunto.IfM
is a method, then all non-method members declared in a base type ofS
are removed from the set.
- Se
- Em seguida, os membros de interface ocultos por membros de classe são removidos do conjunto.Next, interface members that are hidden by class members are removed from the set. Essa etapa só terá efeito se
T
for um parâmetro de tipo eT
tiver uma classe base em vigor diferente deobject
e um conjunto de interfaces efetivas não vazias (restrições de parâmetro de tipo).This step only has an effect ifT
is a type parameter andT
has both an effective base class other thanobject
and a non-empty effective interface set (Type parameter constraints). Para cada membroS.M
no conjunto, em queS
é o tipo no qual o membroM
é declarado, as regras a seguir serão aplicadas seS
for uma declaração de classe diferente deobject
:For every memberS.M
in the set, whereS
is the type in which the memberM
is declared, the following rules are applied ifS
is a class declaration other thanobject
:- Se
M
for uma constante, campo, propriedade, evento, membro de enumeração ou declaração de tipo, todos os membros declarados em uma declaração de interface serão removidos do conjunto.IfM
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
for um método, todos os membros que não forem do método declarados em uma declaração de interface serão removidos do conjunto e todos os métodos com a mesma assinaturaM
declarados em uma declaração de interface serão removidos do conjunto.IfM
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 asM
declared in an interface declaration are removed from the set.
- Se
- Finalmente, ter removido Membros ocultos, o resultado da pesquisa é determinado:Finally, having removed hidden members, the result of the lookup is determined:
- Se o conjunto consistir em um único membro que não seja um método, esse membro será 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 contiver apenas métodos, esse grupo de métodos será 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 será ambígua e ocorrerá um erro de tempo de vinculação.Otherwise, the lookup is ambiguous, and a binding-time error occurs.
Para pesquisas de membros em tipos diferentes de parâmetros de tipo e interfaces, e pesquisas de membros em interfaces que são estritamente herança única (cada interface na cadeia de herança tem exatamente zero ou uma interface de base direta), o efeito das regras de pesquisa é simplesmente que os membros derivados ocultam os membros de 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 podem surgir em relação a pesquisas de membros em interfaces de várias heranças 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, é considerado que um tipo T
tem os seguintes tipos base:For purposes of member lookup, a type T
is considered to have the following base types:
- Se
T
forobject
,T
não terá nenhum tipo base.IfT
isobject
, thenT
has no base type. - Se
T
for um enum_type, os tipos de base doT
são os tipos de classeSystem.Enum
,System.ValueType
eobject
.IfT
is an enum_type, the base types ofT
are the class typesSystem.Enum
,System.ValueType
, andobject
. - Se
T
for um struct_type, os tipos de base doT
são os tipos de classeSystem.ValueType
eobject
.IfT
is a struct_type, the base types ofT
are the class typesSystem.ValueType
andobject
. - Se
T
for um class_type, os tipos base doT
são as classes base doT
, incluindo o tipo de classeobject
.IfT
is a class_type, the base types ofT
are the base classes ofT
, including the class typeobject
. - Se
T
for um interface_type, os tipos de base doT
são as interfaces base doT
e o tipo de classeobject
.IfT
is an interface_type, the base types ofT
are the base interfaces ofT
and the class typeobject
. - Se
T
for um array_type, os tipos de base doT
são os tipos de classeSystem.Array
eobject
.IfT
is an array_type, the base types ofT
are the class typesSystem.Array
andobject
. - Se
T
for um delegate_type, os tipos de base doT
são os tipos de classeSystem.Delegate
eobject
.IfT
is a delegate_type, the base types ofT
are the class typesSystem.Delegate
andobject
.
Membros da funçãoFunction members
Membros de função são membros que contêm instruções Executáveis.Function members are members that contain executable statements. Membros de função são sempre membros de tipos e não podem ser membros de namespaces.Function members are always members of types and cannot be members of namespaces. O C# define as seguintes categorias de membros de 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 destruidores e construtores estáticos (que não podem ser invocados explicitamente), as instruções contidas nos membros da função são executadas por meio de invocações de membro de função.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 gravar uma invocação de membro de função depende da 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 uma invocação de membro de função fornece valores reais ou referências de variáveis 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.
Invocações de métodos genéricos podem empregar inferência de tipos para determinar o conjunto de argumentos de tipo a serem passados 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 tipos.This process is described in Type inference.
Invocações de métodos, indexadores, operadores e construtores de instância empregam resolução de sobrecarga para determinar qual de um conjunto candidato de membros de função 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 de função específico tiver sido identificado no tempo de vinculação, possivelmente por meio da resolução de sobrecarga, o processo real de tempo de execução de invocação do membro da função será descrito em verificação de tempo de compilação da resolução dinâmica de sobrecarga.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 envolvendo as seis categorias de membros de função que podem ser invocadas 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
indicam expressões classificadas como variáveis ou valores, T
indica uma expressão classificada como um tipo, F
é o nome simples de um método e P
é o nome simples 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.
ConstructoConstruct | ExemploExample | DescriçãoDescription |
---|---|---|
Invocação de métodoMethod invocation | F(x,y) |
A resolução de sobrecarga é aplicada para selecionar o melhor método F na classe ou struct que o contém.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 será this .If the method is not static , the instance expression is this . |
T.F(x,y) |
A resolução de sobrecarga é aplicada para selecionar o melhor método F na classe ou estrutura T .Overload resolution is applied to select the best method F in the class or struct T . Ocorrerá um erro de tempo de ligação se o método não for 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) |
A resolução de sobrecarga é aplicada para selecionar o melhor método F na classe, struct ou interface fornecida 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 de tempo de associação ocorrerá se o método for 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 à propriedadeProperty access | P |
O get acessador da propriedade P na classe ou struct que a contém é 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 for somente gravação.A compile-time error occurs if P is write-only. Se P não for static , a expressão de instância será this .If P is not static , the instance expression is this . |
P = value |
O set acessador da propriedade P na classe ou struct que a contém é 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 for somente leitura.A compile-time error occurs if P is read-only. Se P não for static , a expressão de instância será 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. Um erro de tempo de compilação ocorre se P não for static ou se P for 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) . Um erro de tempo de compilação ocorre se P não for static ou se P for 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 fornecida 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 de tempo de associação ocorrerá se P for static ou se P for 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 fornecida 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 de tempo de associação ocorrerá se P for static ou se P for somente leitura.A binding-time error occurs if P is static or if P is read-only. |
|
Acesso a eventosEvent access | E += value |
O add acessador do evento E na classe ou struct que o contém é invocado.The add accessor of the event E in the containing class or struct is invoked. Se E não for estático, a expressão de instância será this .If E is not static, the instance expression is this . |
E -= value |
O remove acessador do evento E na classe ou struct que o contém é invocado.The remove accessor of the event E in the containing class or struct is invoked. Se E não for estático, a expressão de instância será 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 ligação se E não for 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 ligação se E não for 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 fornecida 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 for 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 fornecida 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 for estático.A binding-time error occurs if E is static. |
|
Acesso de indexadorIndexer access | e[x,y] |
A resolução de sobrecarga é aplicada para selecionar o melhor indexador na classe, struct ou interface fornecida 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) . Ocorrerá um erro de tempo de ligação se o indexador for somente gravação.A binding-time error occurs if the indexer is write-only. |
e[x,y] = value |
A resolução de sobrecarga é aplicada para selecionar o melhor indexador na classe, struct ou interface fornecida 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) . Ocorrerá um erro de tempo de ligação se o indexador for somente leitura.A binding-time error occurs if the indexer is read-only. |
|
Invocação de operadorOperator invocation | -x |
A resolução de sobrecarga é aplicada para selecionar o melhor operador unário 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 |
A resolução de sobrecarga é aplicada para selecionar o melhor operador binário nas classes ou estruturas dadas 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 de construtor de instânciaInstance constructor invocation | new T(x,y) |
A resolução de sobrecarga é aplicada para selecionar o melhor Construtor de instância na classe ou estrutura 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 membro de função e invocação de delegado inclui uma lista de argumentos que fornece valores reais ou referências de variáveis 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 da categoria de membro da função:The syntax for specifying the argument list of a function member invocation depends on the function member category:
- Para construtores de instância, 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 também inclui a expressão especificada como o operando à direita do operador de atribuição.For indexers, when invoking theset
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 oset
acessador.For properties, the argument list is empty when invoking theget
accessor, and consists of the expression specified as the right operand of the assignment operator when invoking theset
accessor. - Para eventos, a lista de argumentos consiste na expressão especificada como o operando à direita do
+=
-=
operador OR.For events, the argument list consists of the expression specified as the right operand of the+=
or-=
operator. - Para operadores definidos pelo usuário, a lista de argumentos consiste no único operando do operador unário ou nos 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) são sempre passados como parâmetros de valor (parâmetros de valor).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) são sempre passados como parâmetros de valor (parâmetros de valor) ou matrizes de parâmetro (matrizes de parâmetro).The arguments of indexers (Indexers) are always passed as value parameters (Value parameters) or parameter arrays (Parameter arrays). Parâmetros de referência e saída não têm suporte para essas categorias de membros de função.Reference and output parameters are not supported for these categories of function members.
Os argumentos de um construtor de instância, método, indexador ou invocação de delegado 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
;
Um argument_list consiste em um ou mais s de argumento, separados por vírgulas.An argument_list consists of one or more argument s, separated by commas. Cada argumento consiste em um argument_name opcional seguido por um argument_value.Each argument consists of an optional argument_name followed by an argument_value. Um argumento com um argument_name é chamado de um argumento nomeado , enquanto que 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 que um argumento posicional apareça após um argumento nomeado em um _argument_list *.It is an error for a positional argument to appear after a named argument in an _argument_list*.
O argument_value pode ter um dos seguintes formatos:The argument_value can take one of the following forms:
- Uma expressão, indicando que o argumento é passado como um parâmetro de valor (parâmetros de valor).An expression, indicating that the argument is passed as a value parameter (Value parameters).
- A palavra-chave
ref
seguida por uma variable_reference (referências de variáveis), indicando que o argumento é passado como um parâmetro de referência (parâmetros de referência).The keywordref
followed by a variable_reference (Variable references), indicating that the argument is passed as a reference parameter (Reference parameters). Uma variável deve ser definitivamente atribuída (atribuição definitiva) antes de poder ser passada como um parâmetro de referência.A variable must be definitely assigned (Definite assignment) before it can be passed as a reference parameter. A palavra-chaveout
seguida por uma variable_reference (referências de variáveis), indicando que o argumento é passado como um parâmetro de saída (parâmetros de saída).The keywordout
followed by a variable_reference (Variable references), indicating that the argument is passed as an output parameter (Output parameters). Uma variável é considerada definitivamente atribuída (atribuição definitiva) após uma invocação de membro de função na qual a variável é passada como um parâmetro de saída.A variable is considered definitely assigned (Definite assignment) following a function member invocation in which the variable is passed as an output parameter.
Parâmetros correspondentesCorresponding parameters
Para cada argumento em uma lista de argumentos, deve haver um parâmetro correspondente no membro da função ou no 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 como a seguir:The parameter list used in the following is determined as follows:
- Para métodos virtuais e indexadores definidos em classes, a lista de parâmetros é escolhida da declaração mais específica ou substituição do membro da função, começando com o tipo estático do receptor e pesquisando 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 para formar a definição mais específica do membro, começando com o tipo de interface e pesquisando as 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âmetros exclusiva for encontrada, uma lista de parâmetros com nomes inacessíveis e nenhum parâmetro opcional será construído, de modo que as invocações não poderão usar parâmetros nomeados nem 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, a lista de parâmetros da declaração de método parcial de definição é usada.For partial methods, the parameter list of the defining partial method declaration is used.
- Para todos os outros membros de função e delegados, há apenas uma única lista de parâmetros, que é a 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 parâmetro é definida como o número de argumentos ou parâmetros que o antecedem na lista de argumentos ou na 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 correspondentes para argumentos de membro de função são estabelecidos da seguinte maneira:The corresponding parameters for function member arguments are established as follows:
- Argumentos na 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 fixo 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 de função com uma matriz de parâmetros invocada em seu formato 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 de função com uma matriz de parâmetro invocada em sua forma expandida, em que nenhum parâmetro fixo ocorre 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 aovalue
parâmetro implícito daset
declaração de acessador.For indexers, when invoking theset
accessor, the expression specified as the right operand of the assignment operator corresponds to the implicitvalue
parameter of theset
accessor declaration.
- Para propriedades, ao invocar o
get
acessador, não há argumentos.For properties, when invoking theget
accessor there are no arguments. Ao invocar oset
acessador, a expressão especificada como o operando à direita do operador de atribuição corresponde aovalue
parâmetro implícito daset
declaração de acessador.When invoking theset
accessor, the expression specified as the right operand of the assignment operator corresponds to the implicitvalue
parameter of theset
accessor declaration. - Para operadores unários definidos 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.
- Para 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 de tempo de execução de 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 tempo de compilação da resolução dinâmica de sobrecarga), as expressões ou referências de variáveis de uma lista de argumentos são avaliadas na ordem, da esquerda para a direita, da seguinte maneira: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 tipo de parâmetro correspondente é executada.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 torna-se 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 saída, a referência de variável é avaliada e o local de armazenamento resultante torna-se 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 parâmetro de referência ou de saída for um elemento de matriz de um reference_type, uma verificação de tempo de execução será executada para garantir que o tipo de elemento da matriz seja 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 falhar, um
System.ArrayTypeMismatchException
será lançado.If this check fails, aSystem.ArrayTypeMismatchException
is thrown.
Métodos, indexadores e construtores de instância podem declarar seu parâmetro mais à direita para ser uma matriz de parâmetros (matrizes de parâmetros).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 seu formato normal ou em sua forma expandida, dependendo do que é aplicável (membro de 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 seu formato 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âmetros.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âmetros funciona precisamente 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 seu formato expandido, a invocação deve especificar zero ou mais argumentos posicionais para a matriz de parâmetros, em que cada argumento é uma expressão que é implicitamente conversível (conversões implícitas) 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 matriz de parâmetros com um comprimento correspondente ao número de argumentos, inicializa os elementos da instância de matriz com os valores de argumento fornecidos e usa a instância de matriz recém-criada como o argumento real.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 são sempre avaliadas na ordem em que 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 covariância de matriz (covariância de matriz) permitem que um valor de um tipo de matriz A[]
seja uma referência a uma instância de um tipo de matriz B[]
, desde que exista 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 referência ou de saída, uma verificação de tempo de execução é necessária para garantir que o tipo de elemento real da matriz seja idêntico ao 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 invocação de F
faz com que uma seja System.ArrayTypeMismatchException
gerada porque o tipo de elemento real de 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 seu formato expandido, 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 inserida em volta dos 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 acorrespond 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 são omitidos de um membro de função com parâmetros opcionais correspondentes, os argumentos padrão da declaração de membro de 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. Como elas são sempre 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 tiposType inference
Quando um método genérico é chamado sem especificar argumentos de tipo, um processo de inferência de tipos 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 da inferência de tipos permite que uma sintaxe mais conveniente seja usada para chamar um método genérico e permite que o programador Evite especificar informações de tipo redundante.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 do 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 da inferência de tipos, 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.
A inferência de tipos ocorre como parte do processamento do 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étodos específico é especificado em uma invocação de método e nenhum argumento de tipo é especificado como parte da invocação de método, a inferência de tipos é aplicada a cada método genérico no grupo de métodos.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 tipos for realizada com sucesso, os argumentos de tipo deduzidos serão usados para determinar os tipos de argumentos para resolução de sobrecarga subsequente.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 escolher um método genérico como o para invocar, os argumentos de tipo inferido serã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 inferência de tipos para um determinado método falhar, esse método não participará da resolução de sobrecarga.If type inference for a particular method fails, that method does not participate in overload resolution. A falha da inferência de tipos, por si só, não causa um erro de tempo de ligação.The failure of type inference, in and of itself, does not cause a binding-time error. No entanto, geralmente leva a um erro de tempo de ligação quando a resolução de sobrecarga não 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 de argumentos fornecido for diferente do número de parâmetros no método, a inferência falhará imediatamente.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 tenha 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 da inferência de tipos é encontrar argumentos S1...Sn
de tipo exclusivo para cada um dos parâmetros de tipo X1...Xn
para que a chamada M<S1...Sn>(E1...Em)
se torne válida.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, cada parâmetro Xi
de tipo é corrigido para um tipo específico Si
ou não é corrigido 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 Xi
de tipo não é corrigida com um conjunto vazio de limites.Initially each type variable Xi
is unfixed with an empty set of bounds.
A inferência de tipos ocorre em fases.Type inference takes place in phases. Cada fase tentará inferir argumentos de tipo para mais variáveis de tipo com base nas conclusões 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 iniciais de limites, enquanto a segunda fase corrige variáveis de tipo para tipos específicos e infere limites adicionais.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 repetida várias vezes.The second phase may have to be repeated a number of times.
Observação: A inferência de tipos ocorre não apenas quando um método genérico é chamado.Note: Type inference takes place not only when a generic method is called. A inferência de tipos para a conversão de grupos de métodos é descrita na inferência de tipos para a conversão de grupos de métodos e a localização do melhor tipo comum de um conjunto de expressões é descrita na localização do melhor tipo comum de um conjunto de 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 do método Ei
:For each of the method arguments Ei
:
- Se
Ei
for uma função anônima, uma inferência de tipo de parâmetro explícita (induçãos de tipo de parâmetro explícita) será feita deEi
paraTi
IfEi
is an anonymous function, an explicit parameter type inference (Explicit parameter type inferences) is made fromEi
toTi
- Caso contrário, se
Ei
tiver um tipoU
exi
for um parâmetro de valor, uma inferência de limite inferior será feita deU
paraTi
.Otherwise, ifEi
has a typeU
andxi
is a value parameter then a lower-bound inference is made fromU
toTi
. - Caso contrário, se
Ei
tiver um tipoU
exi
for umref
parâmetro ouout
, uma inferência exata será feita deU
paraTi
.Otherwise, ifEi
has a typeU
andxi
is aref
orout
parameter then an exact inference is made fromU
toTi
. - 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 continua da seguinte maneira:The second phase proceeds as follows:
- Todas as variáveis de tipo não fixas
Xi
que não dependem de (dependência)Xj
são corrigidas (corrigindo).All unfixed type variablesXi
which do not depend on (Dependence) anyXj
are fixed (Fixing). - Se nenhuma dessas variáveis de tipo existir, todas as variáveis de tipo não fixas
Xi
serão corrigidas para cada uma das seguintes isenções:If no such type variables exist, all unfixed type variablesXi
are fixed for which all of the following hold:- Há pelo menos uma variável de tipo
Xj
que depende deXi
There is at least one type variableXj
that depends onXi
Xi
tem um conjunto não vazio de limitesXi
has a non-empty set of bounds
- Há pelo menos uma variável de tipo
- Se nenhuma das variáveis de tipo existirem e ainda houver variáveis de tipo não fixas , a inferência de tipos falhará.If no such type variables exist and there are still unfixed type variables, type inference fails.
- Caso contrário, se nenhuma variável de tipo não fixa existir, a inferência de tipos terá sucesso.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 os tipos de saída (tipos de saída) contêm variáveis de tipo não fixasXj
, mas os tipos de entrada (tipos de entrada) não, uma inferência de tipo de saída (inferências de tipo de saída) é feita deEi
paraTi
.Otherwise, for all argumentsEi
with corresponding parameter typeTi
where the output types (Output types) contain unfixed type variablesXj
but the input types (Input types) do not, an output type inference (Output type inferences) is made fromEi
toTi
. Em seguida, a segunda fase é repetida.Then the second phase is repeated.
Tipos de entradaInput types
Se E
for um grupo de métodos ou uma função anônima digitada implicitamente e T
for um tipo delegado ou tipo de árvore de expressão, todos os tipos de parâmetro de T
serão tipos de entrada de E
com o 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
for um grupo de métodos ou uma função anônima e T
for um tipo delegado ou tipo de árvore de expressão, o tipo de retorno de T
será um tipo de saída E
com o 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 variável de tipo não fixo Xi
depende diretamente de uma variável de tipo não fixa Xj
se, para algum argumento Ek
com tipo Tk
Xj
, ocorrer em um tipo de entrada de Ek
com tipo Tk
e Xi
ocorrer 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 de Xi
Se Xj
depende diretamente do Xi
ou se Xi
depende diretamente de Xk
e Xk
depende de Xj
.Xj
depends on Xi
if Xj
depends directly on Xi
or if Xi
depends directly on Xk
and Xk
depends on Xj
. Assim, "depende" é o fechamento transitivo, mas não reflexivo, de "depende diretamente de".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 de 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 tipo de retorno inferidoU
(tipo de retorno inferido) eT
é um tipo delegado ou tipo de árvore de expressão com tipo de retornoTb
, uma inferência de limite inferior (inferências de limite inferior) é feita deU
paraTb
.IfE
is an anonymous function with inferred return typeU
(Inferred return type) andT
is a delegate type or expression tree type with return typeTb
, then a lower-bound inference (Lower-bound inferences) is made fromU
toTb
. - Caso contrário, se
E
for um grupo de métodos eT
for um tipo delegado ou tipo de árvore de expressão com tipos de parâmetroT1...Tk
e tipoTb
de retorno, e a resolução de sobrecarga deE
com os tiposT1...Tk
gerar um único método com tipo de retornoU
, uma inferência de limite inferior será feita deU
paraTb
.Otherwise, ifE
is a method group andT
is a delegate type or expression tree type with parameter typesT1...Tk
and return typeTb
, and overload resolution ofE
with the typesT1...Tk
yields a single method with return typeU
, then a lower-bound inference is made fromU
toTb
. - Caso contrário, se
E
for uma expressão com tipoU
, uma inferência de limite inferior será feita deU
paraT
.Otherwise, ifE
is an expression with typeU
, then a lower-bound inference is made fromU
toT
. - Caso contrário, nenhuma inferência será feita.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ícita é feita de 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 explicitamente tipada com tipos de parâmetroU1...Uk
eT
é um tipo delegado ou tipo de árvore de expressão com tiposV1...Vk
de parâmetro, então cadaUi
uma das inferências exatas é feita deUi
para o correspondenteVi
.IfE
is an explicitly typed anonymous function with parameter typesU1...Uk
andT
is a delegate type or expression tree type with parameter typesV1...Vk
then for eachUi
an exact inference (Exact inferences) is made fromUi
to the correspondingVi
.
Inferências exatasExact inferences
Uma inferência exata 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
for um dos não corrigidosXi
,U
será adicionado ao conjunto de limites exatos paraXi
.IfV
is one of the unfixedXi
thenU
is added to the set of exact bounds forXi
.Caso contrário, os conjuntos
V1...Vk
eU1...Uk
são determinados verificando se algum dos casos a seguir se aplica:Otherwise, setsV1...Vk
andU1...Uk
are determined by checking if any of the following cases apply:V
é um tipoV1[...]
de matriz eU
é um tipoU1[...]
de matriz da mesma classificaçãoV
is an array typeV1[...]
andU
is an array typeU1[...]
of the same rankV
é o tipoV1?
eU
é o tipoU1?
V
is the typeV1?
andU
is the typeU1?
V
é um tipo construídoC<V1...Vk>
eU
é um tipo construídoC<U1...Uk>
V
is a constructed typeC<V1...Vk>
andU
is a constructed typeC<U1...Uk>
Se qualquer um desses casos se aplicar, uma inferência exata será feita de cada
Ui
para o correspondenteVi
.If any of these cases apply then an exact inference is made from eachUi
to the correspondingVi
.Caso contrário, nenhuma inferência será feita.Otherwise no inferences are made.
Inferências de limite inferiorLower-bound inferences
Uma inferência de limite inferior de 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
for um dos não corrigidosXi
,U
será adicionado ao conjunto de limites inferiores paraXi
.IfV
is one of the unfixedXi
thenU
is added to the set of lower bounds forXi
.Caso contrário, se
V
for o tipoV1?
eU
for o tipoU1?
, uma inferência de limite inferior será feita deU1
paraV1
.Otherwise, ifV
is the typeV1?
andU
is the typeU1?
then a lower bound inference is made fromU1
toV1
.Caso contrário, os conjuntos
U1...Uk
eV1...Vk
são determinados verificando se algum dos casos a seguir se aplica:Otherwise, setsU1...Uk
andV1...Vk
are determined by checking if any of the following cases apply:V
é um tipo de matrizV1[...]
eU
é um tipoU1[...]
de matriz (ou um parâmetro de tipo cujo tipo base efetivo éU1[...]
) da mesma classificaçãoV
is an array typeV1[...]
andU
is an array typeU1[...]
(or a type parameter whose effective base type isU1[...]
) of the same rankV
é um deIEnumerable<V1>
,ICollection<V1>
ouIList<V1>
eU
é um tipo de matriz unidimensionalU1[]
(ou um parâmetro de tipo cujo tipo base é efetivoU1[]
)V
is one ofIEnumerable<V1>
,ICollection<V1>
orIList<V1>
andU
is a one-dimensional array typeU1[]
(or a type parameter whose effective base type isU1[]
)V
é uma classe construída, struct, interface ou tipo delegadoC<V1...Vk>
e há um tipo exclusivoC<U1...Uk>
, de modo queU
(ou, seU
for um parâmetro de tipo, sua classe base efetiva ou qualquer membro de seu conjunto de interface efetivo) seja idêntico a, herda de (direta ou indiretamente) ou implementa (direta ou indiretamente)C<U1...Uk>
.V
is a constructed class, struct, interface or delegate typeC<V1...Vk>
and there is a unique typeC<U1...Uk>
such thatU
(or, ifU
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 de "exclusividade" significa que, na interface do caso
C<T> {} class U: C<X>, C<Y> {}
, nenhuma inferência é feita quando se faz referênciaU
a,C<T>
porqueU1
poderia serX
ouY
.)(The "uniqueness" restriction means that in the case interfaceC<T> {} class U: C<X>, C<Y> {}
, then no inference is made when inferring fromU
toC<T>
becauseU1
could beX
orY
.)
Se qualquer um desses casos se aplicar, uma inferência será feita de cada
Ui
para o correspondente da seguinteVi
maneira:If any of these cases apply then an inference is made from eachUi
to the correspondingVi
as follows:- Se
Ui
não for conhecido como um tipo de referência, uma inferência exata será feitaIfUi
is not known to be a reference type then an exact inference is made - Caso contrário, se
U
for um tipo de matriz, uma inferência de limite inferior será feitaOtherwise, ifU
is an array type then a lower-bound inference is made - Caso contrário, se
V
forC<V1...Vk>
, a inferência dependerá do parâmetro de tipo i-th deC
:Otherwise, ifV
isC<V1...Vk>
then inference depends on the i-th type parameter ofC
:- Se for covariant, uma inferência de limite inferior será feita.If it is covariant then a lower-bound inference is made.
- Se for contravariant, uma inferência de limite superior será feita.If it is contravariant then an upper-bound inference is made.
- Se for invariável, uma inferência exata será feita.If it is invariant then an exact inference is made.
Caso contrário, nenhuma inferência será feita.Otherwise, no inferences are made.
Inferências de limite superiorUpper-bound inferences
Uma inferência 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
for um dos não corrigidosXi
,U
será adicionado ao conjunto de limites superiores paraXi
.IfV
is one of the unfixedXi
thenU
is added to the set of upper bounds forXi
.Caso contrário, os conjuntos
V1...Vk
eU1...Uk
são determinados verificando se algum dos casos a seguir se aplica:Otherwise, setsV1...Vk
andU1...Uk
are determined by checking if any of the following cases apply:U
é um tipoU1[...]
de matriz eV
é um tipoV1[...]
de matriz da mesma classificaçãoU
is an array typeU1[...]
andV
is an array typeV1[...]
of the same rankU
é um deIEnumerable<Ue>
,ICollection<Ue>
ouIList<Ue>
eV
é um tipo de matriz unidimensionalVe[]
U
is one ofIEnumerable<Ue>
,ICollection<Ue>
orIList<Ue>
andV
is a one-dimensional array typeVe[]
U
é o tipoU1?
eV
é o tipoV1?
U
is the typeU1?
andV
is the typeV1?
U
é classe construída, struct, interface ou tipo delegadoC<U1...Uk>
eV
é uma classe, struct, interface ou tipo delegado, que é idêntica a, herda de (direta ou indiretamente) ou implementa (direta ou indiretamente) um tipo exclusivoC<V1...Vk>
U
is constructed class, struct, interface or delegate typeC<U1...Uk>
andV
is a class, struct, interface or delegate type which is identical to, inherits from (directly or indirectly), or implements (directly or indirectly) a unique typeC<V1...Vk>
(A restrição de "exclusividade" significa que, se tivermos
interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}
, nenhuma inferência será feita ao se inferir deC<U1>
paraV<Q>
.(The "uniqueness" restriction means that if we haveinterface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}
, then no inference is made when inferring fromC<U1>
toV<Q>
. As inferências não são feitas noU1
X<Q>
ou noY<Q>
.)Inferences are not made fromU1
to eitherX<Q>
orY<Q>
.)
Se qualquer um desses casos se aplicar, uma inferência será feita de cada
Ui
para o correspondente da seguinteVi
maneira:If any of these cases apply then an inference is made from eachUi
to the correspondingVi
as follows:- Se
Ui
não for conhecido como um tipo de referência, uma inferência exata será feitaIfUi
is not known to be a reference type then an exact inference is made - Caso contrário, se
V
for um tipo de matriz, uma inferência de limite superior será feitaOtherwise, ifV
is an array type then an upper-bound inference is made - Caso contrário, se
U
forC<U1...Uk>
, a inferência dependerá do parâmetro de tipo i-th deC
:Otherwise, ifU
isC<U1...Uk>
then inference depends on the i-th type parameter ofC
:- Se for covariant, uma inferência de limite superior será feita.If it is covariant then an upper-bound inference is made.
- Se for contravariant, uma inferência de limite inferior será feita.If it is contravariant then a lower-bound inference is made.
- Se for invariável, uma inferência exata será feita.If it is invariant then an exact inference is made.
Caso contrário, nenhuma inferência será feita.Otherwise, no inferences are made.
Resolvendo Fixing
Uma variável Xi
de tipo não fixo 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 candidatos
Uj
começa como o conjunto de todos os tipos no conjunto de limites paraXi
.The set of candidate typesUj
starts out as the set of all types in the set of bounds forXi
. - Em seguida, examinamos cada associado por
Xi
vez: para cada limite exatoU
deXi
todos os tiposUj
que não são idênticos aU
são removidos do conjunto candidato.We then examine each bound forXi
in turn: For each exact boundU
ofXi
all typesUj
which are not identical toU
are removed from the candidate set. Para cada limite inferiorU
deXi
todos os tiposUj
para os quais não há uma conversão implícita deU
são removidos do conjunto candidato.For each lower boundU
ofXi
all typesUj
to which there is not an implicit conversion fromU
are removed from the candidate set. Para cada limite superiorU
deXi
todos os tiposUj
dos quais não há uma conversão implícita a serU
removida do conjunto de candidatos.For each upper boundU
ofXi
all typesUj
from which there is not an implicit conversion toU
are removed from the candidate set. - Se entre os tipos candidatos restantes
Uj
, há um tipo exclusivoV
do qual há uma conversão implícita para todos os outros tipos candidatos e, em seguida,Xi
é corrigido paraV
.If among the remaining candidate typesUj
there is a unique typeV
from which there is an implicit conversion to all the other candidate types, thenXi
is fixed toV
. - Caso contrário, a inferência de tipos falhará.Otherwise, type inference fails.
Tipo de retorno inferidoInferred return type
O tipo de retorno inferido de uma função anônima F
é usado durante a inferência de tipos e resolução de sobrecarga.The inferred return type of an anonymous function F
is used during type inference and overload resolution. O tipo de retorno inferido só pode ser determinado para uma função anônima em que todos os tipos de parâmetro são conhecidos, seja porque eles são explicitamente fornecidos, fornecidos por meio de uma conversão de função anônima ou inferido durante a inferência de tipos em uma invocação de método genérico delimitador.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 tipo de resultado deduzido é determinado da seguinte maneira:The inferred result type is determined as follows:
- Se o corpo de
F
for uma expressão que tem um tipo, o tipo de resultado inferido deF
será o tipo dessa expressão.If the body ofF
is an expression that has a type, then the inferred result type ofF
is the type of that expression. - Se o corpo de
F
for um bloco e o conjunto de expressões nas instruções do blocoreturn
tiver um tipo mais comumT
(encontrando o melhor tipo comum de um conjunto de expressões), o tipo de resultado inferido deF
seráT
.If the body ofF
is a block and the set of expressions in the block'sreturn
statements has a best common typeT
(Finding the best common type of a set of expressions), then the inferred result type ofF
isT
. - Caso contrário, não será possível inferir um tipo de resultado para
F
.Otherwise, a result type cannot be inferred forF
.
O tipo de retorno inferido é determinado da seguinte maneira:The inferred return type is determined as follows:
- Se
F
é Async e o corpo deF
é uma expressão classificada como Nothing (classificações de expressão) ou um bloco de instruções em que nenhuma instrução de retorno tem expressões, o tipo de retorno inferido éSystem.Threading.Tasks.Task
IfF
is async and the body ofF
is either an expression classified as nothing (Expression classifications), or a statement block where no return statements have expressions, the inferred return type isSystem.Threading.Tasks.Task
- Se
F
for Async e tiver um tipo de resultado inferidoT
, o tipo de retorno inferido seráSystem.Threading.Tasks.Task<T>
.IfF
is async and has an inferred result typeT
, the inferred return type isSystem.Threading.Tasks.Task<T>
. - Se
F
for não Async e tiver um tipo de resultado inferidoT
, o tipo de retorno inferido seráT
.IfF
is non-async and has an inferred result typeT
, the inferred return type isT
. - Caso contrário, não será possível inferir um tipo de retorno para
F
.Otherwise a return type cannot be inferred forF
.
Como exemplo de inferência de tipos envolvendo funções anônimas, considere o Select
método de extensão declarado na 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 tenha sido importado com uma using
cláusula e dada uma classe Customer
com uma 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 do método de extensão (invocações de método de extensão) do Select
é processada pela regravação da invocação 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 os argumentos de tipo não foram especificados explicitamente, a inferência de tipos é 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 ao source
parâmetro, inferindo-se T
a ser Customer
.First, the customers
argument is related to the source
parameter, inferring T
to be Customer
. Em seguida, o uso do processo de inferência de tipo de função anônima descrito acima c
é fornecido Customer
, e a expressão c.Name
está relacionada ao tipo de retorno do selector
parâmetro, inferindo-se S
a 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 como a inferência de tipo de função anônima permite que informações de tipo "Flow" Entrem 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. Dado 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 tipos para a invocação:Type inference for the invocation:
double seconds = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds);
continua da seguinte maneira: primeiro, o argumento "1:15:30"
está relacionado ao value
parâmetro, inferindo-se X
a ser string
.proceeds as follows: First, the argument "1:15:30"
is related to the value
parameter, inferring X
to be string
. Em seguida, o parâmetro da primeira função anônima, s
, recebe o tipo inferido string
, e a expressão TimeSpan.Parse(s)
está relacionada ao tipo de retorno f1
, inferindo-se Y
a 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.TimeSpan
, e a expressão t.TotalSeconds
está relacionada ao tipo de retorno f2
, inferindo-se Z
a 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
. Assim, o resultado da invocação é do tipo double
.Thus, the result of the invocation is of type double
.
Inferência de tipos para conversão de grupos de métodosType inference for conversion of method groups
Semelhante às chamadas de métodos genéricos, a inferência de tipos também deve ser aplicada quando um grupo de método M
que contém um método genérico é convertido em um determinado tipo de delegado D
(conversões de grupo de métodos).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). Dado um métodoGiven a method
Tr M<X1...Xn>(T1 x1 ... Tm xm)
e o grupo de métodos M
sendo atribuído ao tipo delegado D
a tarefa de tipo inferência é encontrar argumentos de tipo S1...Sn
para 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>
torna-se compatível (delegar declarações) com D
.becomes compatible (Delegate declarations) with D
.
Ao contrário do algoritmo de inferência de tipos para chamadas de método genérico, nesse caso, há apenas tipos de argumento, sem expressões de argumento.Unlike the type inference algorithm for generic method calls, in this case there are only argument types, no argument expressions. Em particular, não existem funções anônimas e, portanto, não há necessidade de várias fases de inferência.In particular, there are no anonymous functions and hence no need for multiple phases of inference.
Em vez disso, todos Xi
são considerados não corrigidos e uma inferência de limite inferior é feita de cada tipo Uj
de argumento de D
para 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 para qualquer um dos Xi
limites não for encontrado, a inferência de tipos falhará.If for any of the Xi
no bounds were found, type inference fails. Caso contrário, todos Xi
são corrigidos para Si
o correspondente, que são o resultado da inferência de tipos.Otherwise, all Xi
are fixed to corresponding Si
, which are the result of type inference.
Encontrando 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 precisa ser inferido 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 elemento de matrizes tipadas implicitamente e os tipos de retorno de funções anônimas com corpos de bloco são encontrados 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 deve ser equivalente à chamada de 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)
pelos Ei
argumentos as.with the Ei
as arguments.
Mais precisamente, a inferência começa com uma variável de tipo não fixa X
.More precisely, the inference starts out with an unfixed type variable X
. As inferências de tipo de saída são então feitas de cada Ei
para X
.Output type inferences are then made from each Ei
to X
. Por fim, X
é fixo e, se for bem-sucedido, o tipo resultante S
será 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 não S
existir, as expressões não terão o melhor tipo comum.If no such S
exists, the expressions have no best common type.
Resolução de sobrecargaOverload resolution
A resolução de sobrecarga é um mecanismo de tempo de ligação para selecionar o melhor membro de função para invocar uma lista de argumentos e um conjunto de membros de funções candidatas.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 a ser invocado nos seguintes contextos distintos em C#:Overload resolution selects the function member to invoke in the following distinct contexts within C#:
- Invocação de um método chamado em um invocation_expression (invocações de método).Invocation of a method named in an invocation_expression (Method invocations).
- Invocação de um construtor de instância chamado em um object_creation_expression (expressões de criação de objeto).Invocation of an instance constructor named in an object_creation_expression (Object creation expressions).
- Invocação de um acessador de indexador por meio de um element_access (acesso de elemento).Invocation of an indexer accessor through an element_access (Element access).
- Invocação de um operador predefinido ou definido pelo usuário referenciado em uma expressão (resolução desobrecarga de operador unário e resolução de sobrecarga de operador binário).Invocation of a predefined or user-defined operator referenced in an expression (Unary operator overload resolution and Binary operator overload resolution).
Cada um desses contextos define o conjunto de membros da função candidata e a lista de argumentos de forma exclusiva, conforme descrito em detalhes nas seções listadas 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 membros) e os métodos em uma classe base não serão candidatos se qualquer método em uma classe derivada for aplicável (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 os membros da função candidata e a lista de argumentos tiverem sido identificados, a seleção do melhor membro de função será 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 candidata aplicável, o melhor membro da função nesse conjunto está localizado.Given the set of applicable candidate function members, the best function member in that set is located. Se o conjunto contiver apenas um membro de função, esse membro de função será o melhor membro de função.If the set contains only one function member, then that function member is the best function member. Caso contrário, o melhor membro da função é o membro de uma função que é melhor do que todos os outros membros da função em relação à lista de argumentos fornecida, desde que cada membro da função seja comparado com todos os outros membros da função usando as regras no melhor membro da função.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 seja melhor do que todos os outros membros da função, a invocação do membro da função será ambígua e ocorrerá um erro de 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 os significados exatos dos termos *membro da função aplicável _ e _ melhor membro da função *.The following sections define the exact meanings of the terms applicable function member _ and _better function member**.
Membro da função aplicávelApplicable function member
Um membro de função é considerado um membro de função aplicável em relação a uma lista de argumentos A
quando todos os itens a seguir são verdadeiros: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 em
A
corresponde a um parâmetro na declaração de membro de função, conforme descrito em parâmetros correspondentes, e qualquer parâmetro ao qual nenhum argumento corresponde é um parâmetro opcional.Each argument inA
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 no
A
, o modo de passagem de parâmetro do argumento (ou seja, valueref
, ouout
) é idêntico ao modo de passagem de parâmetro do parâmetro correspondente eFor each argument inA
, the parameter passing mode of the argument (i.e., value,ref
, orout
) is identical to the parameter passing mode of the corresponding parameter, and- para um parâmetro de valor ou uma matriz de parâmetros, existe uma conversão implícita (conversões implícitas) 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
out
parâmetro ou, o tipo do argumento é idêntico ao tipo do parâmetro correspondente.for aref
orout
parameter, the type of the argument is identical to the type of the corresponding parameter. Afinal, umref
parâmetro ouout
é um alias para o argumento passado.After all, aref
orout
parameter is an alias for the argument passed.
Para um membro de função que inclui uma matriz de parâmetros, se o membro da função for aplicável pelas regras acima, ele será considerado aplicável em seu *formato 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 de função que inclui uma matriz de parâmetros não for aplicável em seu formato normal, o membro da função poderá ser aplicável em seu formato _ * expandido* *: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**:
- O formulário expandido é construído pela substituição da matriz de parâmetros na declaração de membro de função por zero ou mais parâmetros de valor do tipo de elemento da matriz de parâmetros, de modo que o número de argumentos na lista de argumentos
A
corresponda ao número total 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 listA
matches the total number of parameters. SeA
o tiver menos argumentos do 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 poderá ser construída e, portanto, não será aplicável.IfA
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, o formulário expandido será aplicável se para cada argumento no
A
modo de passagem de parâmetro do argumento for idêntico ao modo de passagem de parâmetro do parâmetro correspondente eOtherwise, the expanded form is applicable if for each argument inA
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 um parâmetro de valor criado pela expansão, uma conversão implícita (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
out
parâmetro ou, o tipo do argumento é idêntico ao tipo do parâmetro correspondente.for aref
orout
parameter, the type of the argument is identical to the type of the corresponding parameter.
Melhor membro da funçãoBetter function member
Para fins de determinação do melhor membro de função, uma lista de argumentos desativados A é construída contendo apenas as expressões de argumento em si na ordem em que aparecem na lista de argumentos originais.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.
As listas de parâmetros para cada um dos membros da função candidata são construídos da seguinte maneira:Parameter lists for each of the candidate function members are constructed in the following way:
- O formulário expandido será usado se o membro da função for aplicável somente no formulário expandido.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 que 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 A
de argumentos com um conjunto de expressões de argumento {E1, E2, ..., En}
e dois membros de função aplicáveis Mp
e Mq
com tipos de parâmetro {P1, P2, ..., Pn}
e {Q1, Q2, ..., Qn}
, Mp
é definido como um membro de função melhor do 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 de
Ex
paraQx
não é melhor do que a conversão implícita deEx
paraPx
efor each argument, the implicit conversion fromEx
toQx
is not better than the implicit conversion fromEx
toPx
, and - para pelo menos um argumento, a conversão de
Ex
paraPx
é melhor do que a conversão deEx
paraQx
.for at least one argument, the conversion fromEx
toPx
is better than the conversion fromEx
toQx
.
Ao executar essa avaliação, se Mp
ou Mq
for aplicável em sua forma expandida, Px
ou Qx
se referir a um parâmetro na forma expandida 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.
No caso de sequências de tipo de parâmetro {P1, P2, ..., Pn}
e {Q1, Q2, ..., Qn}
são equivalentes (ou seja Pi
, cada uma tem uma conversão de identidade para o correspondente Qi
), as seguintes regras de quebra de empate 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
for um método não genérico eMq
for um método genérico,Mp
será melhor do queMq
.IfMp
is a non-generic method andMq
is a generic method, thenMp
is better thanMq
. - Caso contrário, se
Mp
é aplicável em seu formato normal eMq
tem umaparams
matriz e é aplicável apenas em sua forma expandida,Mp
é melhor do queMq
.Otherwise, ifMp
is applicable in its normal form andMq
has aparams
array and is applicable only in its expanded form, thenMp
is better thanMq
. - Caso contrário, se
Mp
tiver mais parâmetros declarados do que oMq
,Mp
será melhor do queMq
.Otherwise, ifMp
has more declared parameters thanMq
, thenMp
is better thanMq
. Isso pode ocorrer se ambos os métodos tiveremparams
matrizes e se forem aplicáveis somente em suas formas expandidas.This can occur if both methods haveparams
arrays and are applicable only in their expanded forms. - Caso contrário, se todos os parâmetros de
Mp
tiverem um argumento correspondente, enquanto os argumentos padrão precisarão ser substituídos por pelo menos um parâmetro opcional emMq
,Mp
é melhor do queMq
.Otherwise if all parameters ofMp
have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter inMq
thenMp
is better thanMq
. - Caso contrário, se
Mp
tiver tipos de parâmetro mais específicos do queMq
,Mp
será melhor do queMq
.Otherwise, ifMp
has more specific parameter types thanMq
, thenMp
is better thanMq
. Permita{R1, R2, ..., Rn}
e{S1, S2, ..., Sn}
represente os tipos de parâmetro não instanciados e não expandidos deMp
eMq
.Let{R1, R2, ..., Rn}
and{S1, S2, ..., Sn}
represent the uninstantiated and unexpanded parameter types ofMp
andMq
.Mp
os tipos de parâmetro do são mais específicos que oMq
If, para cada parâmetro,Rx
não é menos específico queSx
e, para pelo menos um parâmetro,Rx
é mais específico queSx
:Mp
's parameter types are more specific thanMq
's if, for each parameter,Rx
is not less specific thanSx
, and, for at least one parameter,Rx
is more specific thanSx
:- Um parâmetro de tipo é menos específico que 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 for mais específico e nenhum argumento de tipo for menos específico do que o 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 do primeiro for mais específico do que o tipo de elemento do segundo.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 for um operador não-comparado e o outro for um operador de aumento, o que não foi levantado será 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
em um tipo T1
e uma conversão implícita C2
que converte de uma expressão E
em um tipo T2
C1
é uma conversão melhor do que C2
se não E
corresponder exatamente T2
e pelo menos uma das seguintes isenções: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:
E
correspondências exatasT1
(expressão exatamente correspondente)E
exactly matchesT1
(Exactly matching Expression)T1
é um destino de conversão melhor do queT2
(melhor destino de conversão)T1
is a better conversion target thanT2
(Better conversion target)
Expressão exatamente correspondenteExactly matching Expression
Dada uma expressão E
e um tipo T
, E
corresponde exatamente T
a se uma das seguintes isenções:Given an expression E
and a type T
, E
exactly matches T
if one of the following holds:
E
tem um tipoS
e uma conversão de identidade existe emS
paraT
E
has a typeS
, and an identity conversion exists fromS
toT
E
é uma função anônima,T
é um tipo delegadoD
ou um tipo de árvore de expressãoExpression<D>
e uma das seguintes isenções:E
is an anonymous function,T
is either a delegate typeD
or an expression tree typeExpression<D>
and one of the following holds:- Um tipo de retorno inferido
X
existe paraE
no contexto da lista de parâmetrosD
(tipo deretorno inferido) e uma conversão de identidade existe deX
para o tipo de retorno deD
An inferred return typeX
exists forE
in the context of the parameter list ofD
(Inferred return type), and an identity conversion exists fromX
to the return type ofD
E
É não Async eD
tem um tipo de retornoY
ouE
é Async eD
tem um tipo de retornoTask<Y>
, e uma das seguintes contém:EitherE
is non-async andD
has a return typeY
orE
is async andD
has a return typeTask<Y>
, and one of the following holds:- O corpo de
E
é uma expressão que corresponde exatamente aY
The body ofE
is an expression that exactly matchesY
- O corpo de
E
é um bloco de instruções em que cada instrução de retorno retorna uma expressão que corresponde exatamente aY
The body ofE
is a statement block where every return statement returns an expression that exactly matchesY
- O corpo de
- Um tipo de retorno inferido
Melhor destino de conversãoBetter conversion target
Considerando dois tipos diferentes T1
e T2
, T1
é um destino de conversão melhor T2
do que se não houver conversão implícita de T2
para T1
Exists e pelo menos uma das seguintes isenções: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 de
T1
paraT2
existeAn implicit conversion fromT1
toT2
exists T1
é um tipo delegadoD1
ou um tipo de árvore de expressãoExpression<D1>
,T2
é um tipo delegadoD2
ou um tipo de árvore de expressãoExpression<D2>
,D1
tem um tipoS1
de retorno e uma das seguintes isenções:T1
is either a delegate typeD1
or an expression tree typeExpression<D1>
,T2
is either a delegate typeD2
or an expression tree typeExpression<D2>
,D1
has a return typeS1
and one of the following holds:D2
está anulando retornoD2
is void returningD2
tem um tipo de retornoS2
eS1
é um destino de conversão melhor do queS2
D2
has a return typeS2
, andS1
is a better conversion target thanS2
T1
éTask<S1>
,T2
éTask<S2>
, eS1
é um destino de conversão melhor do queS2
T1
isTask<S1>
,T2
isTask<S2>
, andS1
is a better conversion target thanS2
T1
éS1
ouS1?
ondeS1
é um tipo integral assinado eT2
éS2
ouS2?
ondeS2
é um tipo integral não assinado.T1
isS1
orS1?
whereS1
is a signed integral type, andT2
isS2
orS2?
whereS2
is an unsigned integral type. Especificamente:Specifically:S1
ésbyte
eS2
ébyte
,ushort
,uint
ouulong
S1
issbyte
andS2
isbyte
,ushort
,uint
, orulong
S1
éshort
eS2
éushort
,uint
, ouulong
S1
isshort
andS2
isushort
,uint
, orulong
S1
éint
eS2
éuint
, ouulong
S1
isint
andS2
isuint
, orulong
S1
élong
eS2
éulong
S1
islong
andS2
isulong
Sobrecarregando em classes genéricasOverloading in generic classes
Embora as assinaturas como declaradas devam ser exclusivas, é possível que a substituição dos argumentos de tipo resulte 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 quebra de sobrecarga da resolução de sobrecarga acima escolherão 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 sobrecargas que são válidas e inválidas de acordo com esta 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 tempo de compilação da resolução dinâmica de sobrecargaCompile-time checking of dynamic overload resolution
Para operações associadas mais dinamicamente, o conjunto de possíveis candidatos para resolução é desconhecido em tempo de compilação.For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. Em determinados casos, no entanto, o conjunto candidato é conhecido em 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
- O método de instância chama onde o receptor não é uma expressão dinâmicaInstance method calls where the receiver is not a dynamic expression
- Chamadas do indexador onde o receptor não é 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 para ver se qualquer uma delas poderia ser aplicada em tempo de execução. Essa verificação consiste nas 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 argumento de tipo que não dependa direta ou indiretamente em um argumento do tipo
dynamic
é inferido usando as regras de inferência de tipo.Partial type inference: Any type argument that does not depend directly or indirectly on an argument of typedynamic
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: a aplicabilidade é verificada de acordo com o membro de função aplicável, mas ignorando 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 em 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ífico.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 ligação já determinou o membro específico para invocar, possivelmente aplicando a resolução de sobrecarga a um conjunto de membros de funções candidatas.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 descrição do 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 da função estática.Static function members. Esses são construtores de instância, métodos estáticos, 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 de função estática são sempre não virtuais.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, acessadores de propriedade de instância e acessadores do indexador.These are instance methods, instance property accessors, and indexer accessors. Os membros da função de instância são não virtuais ou virtuais e são sempre 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 é computada por uma expressão de instância e torna-se 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 asthis
(This access).
O processamento em tempo de execução de uma invocação de membro de função consiste nas etapas a seguir, em que M
é o membro da função e, se M
for um membro da instância, E
é a expressão de 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 de função estática:IfM
is a static function member:- 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.
Se
M
é um membro de função de instância declarado em um value_type:IfM
is an instance function member declared in a value_type:E
é avaliado.E
is evaluated. Se essa avaliação causar uma exceção, nenhuma etapa adicional será executada.If this evaluation causes an exception, then no further steps are executed.- Se
E
não for classificado como uma variável, uma variável local temporária doE
tipo será criada e o valor deE
será atribuído a essa variável.IfE
is not classified as a variable, then a temporary local variable ofE
's type is created and the value ofE
is assigned to that variable.E
é então reclassificado como uma referência a essa variável local temporária.E
is then reclassified as a reference to that temporary local variable. A variável temporária é acessível comothis
emM
, mas não de qualquer outra maneira.The temporary variable is accessible asthis
withinM
, but not in any other way. Portanto, somente quandoE
é uma variável true é possível que o chamador Observe as alterações que oM
fazthis
.Thus, only whenE
is a true variable is it possible for the caller to observe the changes thatM
makes tothis
. - 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 referenciadaE
se torna a variável referenciada porthis
.The variable referenced byE
becomes the variable referenced bythis
.
Se
M
é um membro de função de instância declarado em um reference_type:IfM
is an instance function member declared in a reference_type:E
é avaliado.E
is evaluated. Se essa avaliação causar uma exceção, nenhuma etapa adicional será 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
for um value_type, uma conversão boxing (conversões Boxing) será executada para converterE
em Typeobject
eE
será considerada do tipoobject
nas etapas a seguir.If the type ofE
is a value_type, a boxing conversion (Boxing conversions) is performed to convertE
to typeobject
, andE
is considered to be of typeobject
in the following steps. Nesse caso,M
poderia ser apenas um membro deSystem.Object
.In this case,M
could only be a member ofSystem.Object
. - O valor de
E
é verificado para ser válido.The value ofE
is checked to be valid. Se o valor deE
fornull
, umSystem.NullReferenceException
será lançado e nenhuma etapa adicional será executada.If the value ofE
isnull
, aSystem.NullReferenceException
is thrown and no further steps are executed. - A implementação do membro da função a ser invocada é determinada:The function member implementation to invoke is determined:
- Se o tipo de tempo de associação de
E
for uma interface, o membro da função a ser invocado será a implementação deM
fornecida pelo tipo de tempo de execução da instância referenciada peloE
.If the binding-time type ofE
is an interface, the function member to invoke is the implementation ofM
provided by the run-time type of the instance referenced byE
. Esse membro de função é determinado pela aplicação das regras de mapeamento de interface (mapeamento de interface) para determinar a implementação deM
fornecida pelo tipo de tempo de execução da instância referenciada peloE
.This function member is determined by applying the interface mapping rules (Interface mapping) to determine the implementation ofM
provided by the run-time type of the instance referenced byE
. - Caso contrário, se
M
for um membro da função virtual, o membro da função a ser invocado será a implementação deM
fornecida pelo tipo de tempo de execução da instância referenciada peloE
.Otherwise, ifM
is a virtual function member, the function member to invoke is the implementation ofM
provided by the run-time type of the instance referenced byE
. Esse membro de função é determinado pela aplicação das regras para determinar a implementação mais derivada (métodos virtuais) deM
em relação ao tipo de tempo de execução da instância referenciada peloE
.This function member is determined by applying the rules for determining the most derived implementation (Virtual methods) ofM
with respect to the run-time type of the instance referenced byE
. - Caso contrário,
M
é um membro de função não virtual e o membro da função a ser invocado é oM
próprio.Otherwise,M
is a non-virtual function member, and the function member to invoke isM
itself.
- Se o tipo de tempo de associação de
- A implementação do membro da função determinada na etapa acima é invocada.The function member implementation determined in the step above is invoked. O objeto referenciado
E
se torna o objeto referenciado porthis
.The object referenced byE
becomes the object referenced bythis
.
Invocações em instâncias em caixasInvocations on boxed instances
Um membro de função implementado em um value_type pode ser invocado por meio de uma instância em caixa do que 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 tipoobject
e é invocado por meio de uma expressão de instância do tipoobject
.When the function member is anoverride
of a method inherited from typeobject
and is invoked through an instance expression of typeobject
. - 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 em caixa é considerada para conter uma variável do value_type, e essa variável se torna a variável referenciada por this
dentro da 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 de função é invocado em uma instância em caixa, é possível que o membro da função modifique o valor contido na instância em caixa.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
As 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
;
As expressões primárias são divididas entre array_creation_expression s e primary_no_array_creation_expression s.Primary expressions are divided between array_creation_expression s and primary_no_array_creation_expression s. Tratar a expressão de criação de matriz dessa maneira, em vez de listá-la junto com outros formulários de expressão simples, permite que a gramática inpermita códigos potencialmente confusos, 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];
que, de outra forma, seriam 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
Um interpolated_string_expression consiste em um $
sinal seguido por um literal de cadeia de caracteres regular ou textual, no qual os buracos, delimitados por {
e }
, incluem expressões e especificações de formatação.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 um interpolated_string_literal que foi dividido em tokens individuais, conforme descrito em literais de cadeia de caracteres interpolados.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 em uma interpolação deve ter uma conversão implícita para int
.The constant_expression in an interpolation must have an implicit conversion to int
.
Um interpolated_string_expression é classificado como um valor.An interpolated_string_expression is classified as a value. Se ele for imediatamente convertido em System.IFormattable
ou System.FormattableString
com uma conversão de cadeia de caracteres interpolada implícita (conversões de cadeia de caracteres interpoladas implícitas), a expressão de cadeia de caracteres interpolada terá 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 terá o tipo string
.Otherwise, it has the type string
.
Se o tipo de uma cadeia de caracteres interpolada for System.IFormattable
ou System.FormattableString
, o significado será 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 será 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 um literal de cadeia de caracteres de formato com espaços reservados para cada interpolação e um argumento para cada expressão correspondente aos detentores de lugar.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, em que N
é o número de interpolações no 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 seguir o
$
sinal, o literal da cadeia de caracteres de formato será 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, o literal de cadeia de caracteres de formato consiste em:Otherwise, the format string literal consists of:
- Primeiro 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
de0
aN-1
:Then for each numberI
from0
toN-1
:- A representação decimal de
I
The decimal representation ofI
- Em seguida, se a interpolação correspondente tiver um constant_expression, um
,
(vírgula) seguido pela representação decimal do valor do 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, o 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.
- A representação decimal de
Os argumentos subsequentes são simplesmente as expressões das interpolações (se houver), em 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?
;
Uma Simple_name é uma das formas I
ou do formulário I<A1,...,Ak>
, em que I
é um único identificador e <A1,...,Ak>
é uma type_argument_list opcional.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 for especificado, considere K
ser zero.When no type_argument_list is specified, consider K
to be zero. A Simple_name é avaliada e classificada da seguinte maneira:The simple_name is evaluated and classified as follows:
Se
K
for zero e o Simple_name aparecer dentro de um bloco e se o espaço de declaração local (declarações) do bloco(ou um bloco delimitador) contiver uma variável local, um parâmetro ou uma constante com nomeI
, o Simple_name se referirá a essa variável local, parâmetro ou constante e será classificado como uma variável ou um valor.IfK
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 nameI
, then the simple_name refers to that local variable, parameter or constant and is classified as a variable or value.Se
K
for zero e o Simple_name aparecer dentro do corpo de uma declaração de método genérico e se essa declaração incluir um parâmetro de tipo com nomeI
, o Simple_name se referirá a esse parâmetro de tipo.IfK
is zero and the simple_name appears within the body of a generic method declaration and if that declaration includes a type parameter with nameI
, 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 da declaração de tipo delimitadora imediatamente e continuando com o tipo de instância de cada declaração de classe ou struct de delimitador (se houver):Otherwise, for each instance typeT
(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
for zero e a declaração deT
incluir um parâmetro de tipo comI
o nome, o Simple_name se referirá a esse parâmetro de tipo.IfK
is zero and the declaration ofT
includes a type parameter with nameI
, then the simple_name refers to that type parameter. - Caso contrário, se uma pesquisa de membro (pesquisa de membro) de
I
emT
com argumentos deK
tipo produzir uma correspondência:Otherwise, if a member lookup (Member lookup) ofI
inT
withK
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étodos com uma expressão de instância associada dethis
.IfT
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 ofthis
. Se uma lista de argumentos de tipo tiver sido especificada, ela será usada 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
for o tipo de instância do tipo de classe ou struct imediatamente delimitadora, se a pesquisa identificar um membro de instância e se a referência ocorrer no corpo de um construtor de instância, um método de instância ou um acessador de instância, o resultado será o mesmo que um acesso de membro (acesso de membro) do formuláriothis.I
.Otherwise, ifT
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 formthis.I
. Isso só pode acontecer quandoK
é zero.This can only happen whenK
is zero. - Caso contrário, o resultado será o mesmo que um acesso de membro (acesso de membro) do formulário
T.I
ouT.I<A1,...,Ak>
.Otherwise, the result is the same as a member access (Member access) of the formT.I
orT.I<A1,...,Ak>
. Nesse caso, é um erro de tempo de associação para o Simple_name fazer referência 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.
- Se
- Se
Caso contrário, para cada namespace
N
, começando com o namespace no qual o Simple_name ocorre, continuando com cada namespace delimitador (se houver) e terminando com o namespace global, as etapas a seguir são avaliadas até que uma entidade esteja localizada:Otherwise, for each namespaceN
, 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
for zero eI
for o nome de um namespace emN
, então:IfK
is zero andI
is the name of a namespace inN
, then:- Se o local onde a Simple_name ocorre estiver entre uma declaração de namespace para
N
e a declaração de namespace contiver um extern_alias_directive ou using_alias_directive que associa o nome aI
um namespace ou tipo, o Simple_name será ambíguo e ocorrerá um erro em tempo de compilação.If the location where the simple_name occurs is enclosed by a namespace declaration forN
and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameI
with a namespace or type, then the simple_name is ambiguous and a compile-time error occurs. - Caso contrário, o Simple_name se refere ao namespace chamado
I
emN
.Otherwise, the simple_name refers to the namespace namedI
inN
.
- Se o local onde a Simple_name ocorre estiver entre uma declaração de namespace para
- Caso contrário, se
N
contiver um tipo acessível comI
parâmetros Name eK
Type, então:Otherwise, ifN
contains an accessible type having nameI
andK
type parameters, then:- Se
K
for zero e o local em que o Simple_name ocorrer é incluído por uma declaração de namespace paraN
e a declaração de namespace contém um extern_alias_directive ou using_alias_directive que associa o nome aI
um namespace ou tipo, o Simple_name é ambíguo e ocorre um erro em tempo de compilação.IfK
is zero and the location where the simple_name occurs is enclosed by a namespace declaration forN
and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameI
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 se refere ao tipo construído com os argumentos de tipo fornecidos.Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
- Se
- Caso contrário, se o local em que o Simple_name ocorrer for 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 forN
:- Se
K
for zero e a declaração de namespace contiver um extern_alias_directive ou using_alias_directive que associa o nome aI
um namespace ou tipo importado, a Simple_name se referirá a esse namespace ou tipo.IfK
is zero and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameI
with an imported namespace or type, then the simple_name refers to that namespace or type. - Caso contrário, se os namespaces e as declarações de tipo importados pelo using_namespace_directive s e using_static_directive s da declaração de namespace contiverem exatamente um tipo acessível ou um membro estático sem extensão que tenha parâmetros de nome
I
eK
tipo, o Simple_name se referirá a esse tipo ou membro construído com os argumentos de tipo fornecidos.Otherwise, if the namespaces and type declarations imported by the using_namespace_directive s and using_static_directive s of the namespace declaration contain exactly one accessible type or non-extension static member having nameI
andK
type parameters, then the simple_name refers to that type or member constructed with the given type arguments. - Caso contrário, se os namespaces e os tipos importados pelo using_namespace_directive s da declaração de namespace contiverem mais de um tipo acessível ou membro estático de método não-extensão que possua parâmetros de nome
I
eK
tipo, o Simple_name será ambíguo e ocorrerá um erro.Otherwise, if the namespaces and types imported by the using_namespace_directive s of the namespace declaration contain more than one accessible type or non-extension-method static member having nameI
andK
type parameters, then the simple_name is ambiguous and an error occurs.
- Se
Observe que essa etapa inteira é exatamente paralela à etapa correspondente no processamento de um namespace_or_type_name (namespace e nomes de 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).
- Se
Caso contrário, o Simple_name será indefinido e ocorrerá um erro em tempo de compilação.Otherwise, the simple_name is undefined and a compile-time error occurs.
Expressões entre parêntesesParenthesized expressions
Uma parenthesized_expression consiste em uma expressão entre parênteses.A parenthesized_expression consists of an expression enclosed in parentheses.
parenthesized_expression
: '(' expression ')'
;
Uma parenthesized_expression é avaliada avaliando a expressão dentro dos parênteses.A parenthesized_expression is evaluated by evaluating the expression within the parentheses. Se a 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 da parenthesized_expression é o resultado da avaliação da expressão contida.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'
;
A produção qualified_alias_member é definida em qualificadores de alias de namespace.The qualified_alias_member production is defined in Namespace alias qualifiers.
Uma member_access é uma das formas E.I
ou do formulário E.I<A1, ..., Ak>
, em que E
é uma expressão primária, I
é um único identificador e <A1, ..., Ak>
é uma type_argument_list opcional.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 for especificado, considere K
ser zero.When no type_argument_list is specified, consider K
to be zero.
Um member_access com um primary_expression do tipo dynamic
é vinculado dinamicamente (associaçã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 da member_access são entã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.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 um 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.
A member_access é avaliada e classificada da seguinte maneira:The member_access is evaluated and classified as follows:
- Se
K
for zero eE
for um namespace eE
contiver um namespace aninhado com nomeI
, o resultado será o namespace.IfK
is zero andE
is a namespace andE
contains a nested namespace with nameI
, then the result is that namespace. - Caso contrário, se
E
for um namespace eE
contiver um tipo acessível com parâmetros de nomeI
eK
tipo, o resultado será aquele tipo construído com os argumentos de tipo fornecidos.Otherwise, ifE
is a namespace andE
contains an accessible type having nameI
andK
type parameters, then the result is that type constructed with the given type arguments. - Se
E
for um predefined_type ou um primary_expression classificado como um tipo, seE
não for um parâmetro de tipo, e se uma pesquisa de membro (pesquisa de membro) deI
noE
com parâmetros deK
tipo produzir uma correspondência, oE.I
será avaliado e classificado da seguinte maneira:IfE
is a predefined_type or a primary_expression classified as a type, ifE
is not a type parameter, and if a member lookup (Member lookup) ofI
inE
withK
type parameters produces a match, thenE.I
is evaluated and classified as follows:- Se
I
o identificar um tipo, o resultado será aquele tipo construído com os argumentos de tipo fornecidos.IfI
identifies a type, then the result is that type constructed with the given type arguments. - Se
I
o identificar um ou mais métodos, o resultado será um grupo de métodos sem nenhuma expressão de instância associada.IfI
identifies one or more methods, then the result is a method group with no associated instance expression. Se uma lista de argumentos de tipo tiver sido especificada, ela será usada 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
o identificar umastatic
propriedade, o resultado será um acesso de propriedade sem nenhuma expressão de instância associada.IfI
identifies astatic
property, then the result is a property access with no associated instance expression. - Se
I
o identificar umstatic
campo:IfI
identifies astatic
field:- Se o campo for
readonly
e a referência ocorrer fora do construtor estático da classe ou struct no qual o campo é declarado, o resultado será um valor, ou seja, o valor do campo estáticoI
emE
.If the field isreadonly
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 fieldI
inE
. - Caso contrário, o resultado será uma variável, ou seja, o campo estático
I
emE
.Otherwise, the result is a variable, namely the static fieldI
inE
.
- Se o campo for
- Se
I
o identificar umstatic
evento:IfI
identifies astatic
event:- Se a referência ocorrer na classe ou struct na qual o evento é declarado e o evento tiver sido declarado sem event_accessor_declarations (eventos),
E.I
será processado exatamente como seI
fosse 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), thenE.I
is processed exactly as ifI
were a static field. - Caso contrário, o resultado será um acesso de evento sem nenhuma expressão de instância associada.Otherwise, the result is an event access with no associated instance expression.
- Se a referência ocorrer na classe ou struct na qual o evento é declarado e o evento tiver sido declarado sem event_accessor_declarations (eventos),
- Se
I
o identificar uma constante, o resultado será um valor, ou seja, o valor dessa constante.IfI
identifies a constant, then the result is a value, namely the value of that constant. - Se
I
o identificar um membro de enumeração, o resultado será um valor, ou seja, o valor desse membro de enumeração.IfI
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álida e ocorre um erro de tempo de compilação.Otherwise,E.I
is an invalid member reference, and a compile-time error occurs.
- Se
- Se
E
for um acesso de propriedade, acesso ao indexador, variável ou valor, o tipo de que éT
, e uma pesquisa de membro (pesquisa de membro) deI
emT
com argumentos deK
tipo produzem uma correspondência, entãoE.I
é avaliado e classificado da seguinte maneira:IfE
is a property access, indexer access, variable, or value, the type of which isT
, and a member lookup (Member lookup) ofI
inT
withK
type arguments produces a match, thenE.I
is evaluated and classified as follows:- Primeiro, se
E
for um acesso de propriedade ou indexador, o valor da propriedade ou do acesso do indexador será obtido (valores de expressões) eE
será reclassificado como um valor.First, ifE
is a property or indexer access, then the value of the property or indexer access is obtained (Values of expressions) andE
is reclassified as a value. - Se
I
o identificar um ou mais métodos, o resultado será um grupo de métodos com uma expressão de instância associada deE
.IfI
identifies one or more methods, then the result is a method group with an associated instance expression ofE
. Se uma lista de argumentos de tipo tiver sido especificada, ela será usada 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
o identificar uma propriedade de instância,IfI
identifies an instance property,- Se
E
forthis
,I
identifica uma propriedade implementada automaticamente (Propriedades implementadas automaticamente) sem um setter, e a referência ocorre dentro de um construtor de instância para um tipo de classe ou structT
, então o resultado é uma variável, ou seja, o campo de apoio oculto para a propriedade automática fornecida porI
na instância doT
fornecida pelothis
.IfE
isthis
,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 typeT
, then the result is a variable, namely the hidden backing field for the auto-property given byI
in the instance ofT
given bythis
. - Caso contrário, o resultado é um acesso de propriedade com uma expressão de instância associada de
E
.Otherwise, the result is a property access with an associated instance expression ofE
.
- Se
- Se
T
é um class_type eI
identifica um campo de instância desse class_type:IfT
is a class_type andI
identifies an instance field of that class_type:- Se o valor de
E
fornull
, umSystem.NullReferenceException
será lançado.If the value ofE
isnull
, then aSystem.NullReferenceException
is thrown. - Caso contrário, se o campo for
readonly
e a referência ocorrer fora de um construtor de instância da classe na qual o campo é declarado, o resultado será um valor, ou seja, o valor do campoI
no objeto referenciado porE
.Otherwise, if the field isreadonly
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 fieldI
in the object referenced byE
. - Caso contrário, o resultado será uma variável, ou seja, o campo
I
no objeto referenciado porE
.Otherwise, the result is a variable, namely the fieldI
in the object referenced byE
.
- Se o valor de
- Se
T
é um struct_type eI
identifica um campo de instância desse struct_type:IfT
is a struct_type andI
identifies an instance field of that struct_type:- Se
E
for um valor, ou se o campo forreadonly
e a referência ocorrer fora de um construtor de instância do struct no qual o campo é declarado, o resultado será um valor, ou seja, o valor do campoI
na instância de struct fornecida porE
.IfE
is a value, or if the field isreadonly
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 fieldI
in the struct instance given byE
. - Caso contrário, o resultado será uma variável, ou seja, o campo
I
na instância de struct fornecida porE
.Otherwise, the result is a variable, namely the fieldI
in the struct instance given byE
.
- Se
- Se
I
o identificar um evento de instância:IfI
identifies an instance event:- Se a referência ocorrer dentro da classe ou estrutura na qual o evento é declarado e o evento tiver sido declarado sem event_accessor_declarations (eventos) e a referência não ocorrer como o lado esquerdo de um
+=
-=
operador OR,E.I
será processada exatamente como seI
fosse 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, thenE.I
is processed exactly as ifI
was an instance field. - Caso contrário, o resultado é um acesso de evento com uma expressão de instância associada de
E
.Otherwise, the result is an event access with an associated instance expression ofE
.
- Se a referência ocorrer dentro da classe ou estrutura na qual o evento é declarado e o evento tiver sido declarado sem event_accessor_declarations (eventos) e a referência não ocorrer como o lado esquerdo de um
- Primeiro, se
- Caso contrário, será feita uma tentativa de 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 processE.I
as an extension method invocation (Extension method invocations). Se isso falhar,E.I
será uma referência de membro inválida e ocorrerá um erro de tempo de vinculação.If this fails,E.I
is an invalid member reference, and a binding-time error occurs.
Nomes de tipos e nomes simples idênticosIdentical simple names and type names
Em um acesso de membro do formulário E.I
, se E
for um único identificador e, se o significado de E
um Simple_name (nomes simples) for uma constante, campo, propriedade, variável local ou parâmetro com o mesmo tipo que o significado de E
um type_name (namespace e nomes de tipo), então ambos os significados possíveis de E
são permitidos.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 do E.I
são nunca ambíguos, pois I
deve necessariamente 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 o acesso aos membros estáticos e tipos aninhados de E
onde um erro de tempo de compilação teria ocorrido de outra forma.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 gramaticaisGrammar ambiguities
As produções para Simple_name (nomes simples) e member_access (acesso de membro) podem dar ao aumento das ambiguidades na gramática para 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 pode 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 puder ser analisada (no contexto) como um Simple_name (nomes simples), member_access (acesso de membro) ou pointer_member_access (acesso de membro de ponteiro) terminando com um type_argument_list (argumentos de tipo), o token imediatamente após o token de fechamento >
é 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 for um deIf it is one of
( ) ] } : ; , . ? == != | ^
em seguida, a type_argument_list é mantida como parte da Simple_name, member_access ou pointer_member_access e qualquer outra análise possível da sequência de tokens é 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 será considerado como parte do Simple_name, member_access ou pointer_member_access, mesmo que não haja outra análise possível da sequência de tokens.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 ao analisar um type_argument_list em um namespace_or_type_name (namespace e nomes de 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));
de acordo com essa regra, 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.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 um será interpretado 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 operador, e operador de adição unário, como se a instrução tivesse sido gravada x = (F < A) > (+y)
, em vez de um Simple_name com um type_argument_list seguido por um operador Binary Plus.will be interpreted as a less than operator, greater than operator, and unary plus operator, as if the statement had been written x = (F < A) > (+y)
, instead of as a simple_name with a type_argument_list followed by a binary plus operator. Na instruçãoIn the statement
x = y is C<T> + z;
os tokens C<T>
são interpretados como um 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
Um 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 é vinculada dinamicamente (associação dinâmica) se pelo menos uma das seguintes isenções:An invocation_expression is dynamically bound (Dynamic binding) if at least one of the following holds:
- O primary_expression tem tipo de tempo de compilação
dynamic
.The primary_expression has compile-time typedynamic
. - Pelo menos um argumento da argument_list opcional tem o tipo de tempo de compilação
dynamic
e o primary_expression não tem um tipo delegado.At least one argument of the optional argument_list has compile-time typedynamic
and the primary_expression does not have a delegate type.
Nesse caso, o compilador classifica o 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 são então aplicadas em tempo de execução, usando o tipo de tempo de execução em vez do tipo de tempo de compilação dos argumentos de primary_expression e 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 tiver o tipo de tempo de compilação dynamic
, a invocação de método passará por uma verificação de tempo de compilação limitada, conforme descrito em verificação de tempo de compilação da resolução dinâmica de sobrecarga.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 um invocation_expression deve ser um grupo de métodos 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 for um grupo de métodos, a invocation_expression será 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 for um valor de um delegate_type, o invocation_expression será uma invocação de delegado (invocações de delegado).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 for um grupo de métodos nem um valor de um delegate_type, ocorrerá um erro de 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.
O argument_list opcional (listas de argumentos) fornece 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 um invocation_expression é classificado da seguinte maneira:The result of evaluating an invocation_expression is classified as follows:
- Se o invocation_expression invocar um método ou delegado que retorna
void
, o resultado será Nothing.If the invocation_expression invokes a method or delegate that returnsvoid
, the result is nothing. Uma expressão que é classificada como nada é permitida apenas no contexto de uma statement_expression (instruções de expressão) ou como o corpo de uma lambda_expression (expressões de função anônimas).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 de tempo de vinculação.Otherwise a binding-time error occurs. - Caso contrário, o resultado será um valor do tipo retornado pelo método ou delegado.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, a primary_expression do invocation_expression deve ser um grupo de métodos.For a method invocation, the primary_expression of the invocation_expression must be a method group. O grupo de métodos identifica o método a ser invocado ou o conjunto de métodos sobrecarregados do qual escolher um método específico a ser invocado.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 a ser invocado é baseada no contexto fornecido pelos tipos dos argumentos na 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)
, em que M
é um grupo de métodos (possivelmente incluindo um type_argument_list) e A
é um argument_list opcional, consiste nas 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 candidatos para a invocação do método é construído.The set of candidate methods for the method invocation is constructed. Para cada método
F
associado ao grupo de métodosM
:For each methodF
associated with the method groupM
:- Se
F
for não genérico,F
será um candidato quando:IfF
is non-generic,F
is a candidate when:M
Não tem nenhuma lista de argumentos de tipo eM
has no type argument list, andF
é aplicável em relação aA
(membro de função aplicável).F
is applicable with respect toA
(Applicable function member).
- Se
F
é genérico eM
não tem nenhuma lista de argumentos de tipo,F
é um candidato quando:IfF
is generic andM
has no type argument list,F
is a candidate when:- A inferência de tipos (inferência de tipos) é bem sucedido, inferindo-se a 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 inferido são substituídos pelos parâmetros de tipo de método correspondentes, todos os tipos construídos na lista de parâmetros de F satisfazem suas restrições (atendendo às restrições) e a lista de parâmetros de
F
é aplicável em relação aoA
(membro de 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 ofF
is applicable with respect toA
(Applicable function member).
- Se
F
é genérico eM
inclui uma lista de argumentos de tipo,F
é um candidato quando:IfF
is generic andM
includes a type argument list,F
is a candidate when:F
tem o mesmo número de parâmetros de tipo de método que 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 pelos parâmetros de tipo de método correspondentes, todos os tipos construídos na lista de parâmetros de F satisfazem suas restrições (atendendo às restrições) e a lista de parâmetros de
F
é aplicável em relação aoA
(membro de 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 ofF
is applicable with respect toA
(Applicable function member).
- Se
- O conjunto de métodos candidatos é reduzido para conter apenas métodos dos tipos mais derivados: para cada método
C.F
no conjunto, em queC
é o tipo no qual o métodoF
é declarado, todos os métodos declarados em um tipo base deC
são removidos do conjunto.The set of candidate methods is reduced to contain only methods from the most derived types: For each methodC.F
in the set, whereC
is the type in which the methodF
is declared, all methods declared in a base type ofC
are removed from the set. Além disso, seC
for um tipo de classe diferente deobject
, todos os métodos declarados em um tipo de interface serão removidos do conjunto.Furthermore, ifC
is a class type other thanobject
, all methods declared in an interface type are removed from the set. (Essa última regra só afeta quando o grupo de métodos era o resultado de uma pesquisa de membro em um parâmetro de tipo com uma classe base efetiva diferente de Object e uma interface efetiva não vazia definida.)(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 resultante de métodos candidatos estiver vazio, o processamento adicional nas etapas a seguir será abandonado e, em vez disso, será feita uma tentativa de processar a invocação como 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, não existirá nenhum método aplicável e ocorrerá um erro de 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 candidatos é identificado usando as regras de resolução de sobrecarga da 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 puder ser identificado, a invocação do método será ambígua e ocorrerá um erro de tempo de ligaçã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 após a substituição dos argumentos de tipo (fornecidos ou inferidos) para os parâmetros de tipo de método correspondentes.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.
- A validação final do melhor método escolhido é executada:Final validation of the chosen best method is performed:
- O método é validado no contexto do grupo de métodos: se o melhor método é um método estático, o grupo de métodos deve ter resultado de um Simple_name ou de 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 for um método de instância, o grupo de métodos deverá ter resultado de uma Simple_name, uma member_access por meio de uma variável ou 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 verdadeiro, ocorrerá um erro de tempo de ligação.If neither of these requirements is true, a binding-time error occurs.
- Se o melhor método for um método genérico, os argumentos de tipo (fornecidos ou inferidos) serão verificados em relação às restrições (atendendo às restrições) declaradas 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 atender às restrições correspondentes 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 tiver sido selecionado e validado em tempo de vinculação pelas etapas acima, a invocação de tempo de execução real será processada de acordo com as regras de invocação de membro de função descrita na verificação de tempo de compilação da resolução dinâmica de sobrecarga.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 descritas acima é o seguinte: 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 continue a cadeia de herança até que pelo menos uma declaração de método aplicável, acessível e não substituída seja 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, execute a inferência de tipos e a resolução de sobrecarga no conjunto de métodos aplicáveis, acessíveis e não substituição declarados nesse tipo e invoque o método, portanto, selecionado.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 como 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 em caixas) de um dos formuláriosIn 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 da invocação não encontrar nenhum método aplicável, será feita uma tentativa de processar a construção como 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 tiver tipo de tempo de compilação dynamic
, os métodos de extensão não serão aplicados.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
, para que a invocação de método estático correspondente possa 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
será elegível se:An extension method Ci.Mj
is eligible if:
Ci
é uma classe não genérica e não aninhadaCi
is a non-generic, non-nested class- O nome do
Mj
é identificadorThe name ofMj
is identifier Mj
é acessível e aplicável quando aplicado aos argumentos como um método estático, conforme mostrado acimaMj
is accessible and applicable when applied to the arguments as a static method as shown above- Existe uma identidade implícita, uma referência ou uma conversão boxing de 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 ofMj
.
A pesquisa do C
continua da seguinte maneira:The search for C
proceeds as follows:
- Começando com a declaração de namespace delimitadora mais próxima, continuando com cada declaração de namespace delimitadora e terminando com a unidade de compilação que a contém, as tentativas sucessivas são feitas para encontrar um conjunto candidato 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 o namespace ou a unidade de compilação fornecida diretamente contiver declarações de tipo não genéricas
Ci
com métodos de extensão qualificadosMj
, o conjunto desses métodos de extensão será o conjunto de candidatos.If the given namespace or compilation unit directly contains non-generic type declarationsCi
with eligible extension methodsMj
, then the set of those extension methods is the candidate set. - Se tipos
Ci
importados por using_static_declarations e declarados diretamente em namespaces importados por using_namespace_directive s no namespace ou na unidade de compilação fornecida diretamente contiverem métodos de extensão qualificadosMj
, o conjunto desses métodos de extensão será o conjunto de candidatos.If typesCi
imported by using_static_declarations and directly declared in namespaces imported by using_namespace_directive s in the given namespace or compilation unit directly contain eligible extension methodsMj
, then the set of those extension methods is the candidate set.
- Se o namespace ou a unidade de compilação fornecida diretamente contiver declarações de tipo não genéricas
- Se nenhum conjunto candidato for encontrado em qualquer declaração de namespace ou unidade de compilação delimitadora ocorrer um erro em 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 será aplicada ao conjunto de candidatos, conforme descrito em (resolução de sobrecarga).Otherwise, overload resolution is applied to the candidate set as described in (Overload resolution). Se nenhum único método melhor for encontrado, ocorrerá um erro em 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 C
como um destino, a chamada de método é processada como uma invocação de método estático (verificação de tempo de compilação da resolução dinâmica de sobrecarga).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 anteriores significam que os métodos de instância têm precedência sobre os métodos de extensão, que os métodos de extensão disponíveis nas declarações de namespace interno têm precedência sobre os métodos de extensão disponíveis nas declarações de namespace externo e que os métodos de extensão declarados diretamente em um namespace têm precedência sobre os métodos de extensão importados para o mesmo namespace com uma diretiva de namespace using.The preceding rules mean that instance methods take precedence over extension methods, that extension methods available in inner namespace declarations take precedence over extension methods available in outer namespace declarations, and that extension methods declared directly in a namespace take precedence over extension methods imported into that same namespace with a using namespace directive. 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, o B
método tem precedência sobre o primeiro método de extensão, e o C
método de 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.F
e tem precedência sobre D.F
e C.F
.D.G
takes precedence over C.G
, and E.F
takes precedence over both D.F
and C.F
.
Delegar invocaçõesDelegate invocations
Para uma invocação de delegado, a primary_expression do 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 que a delegate_type seja um membro de função com a mesma lista de parâmetros que a delegate_type, a delegate_type deve ser aplicável (membro de função aplicável) em relação ao argument_list do 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 em tempo de execução de uma invocação de delegado do formulário D(A)
, em que D
é uma primary_expression de um delegate_type e A
é um argument_list opcional, consiste nas 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 causar uma exceção, nenhuma etapa adicional será executada.If this evaluation causes an exception, no further steps are executed.- O valor de
D
é verificado para ser válido.The value ofD
is checked to be valid. Se o valor deD
fornull
, umSystem.NullReferenceException
será lançado e nenhuma etapa adicional será executada.If the value ofD
isnull
, aSystem.NullReferenceException
is thrown and no further steps are executed. - Caso contrário,
D
é uma referência a uma instância delegada.Otherwise,D
is a reference to a delegate instance. Invocações de membro de função (verificação de tempo de compilação de resolução dinâmica de sobrecarga) são executadas em cada uma das entidades que podem 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 podem ser chamadas que consistem em um método de instância e instância, a instância para a invocação é a instância contida na entidade que pôde 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 a elementoElement access
Um 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 s de argumento, separados por vírgulas.The argument_list consists of one or more argument s, separated by commas.
element_access
: primary_no_array_creation_expression '[' expression_list ']'
;
O argument_list de um element_access não tem permissão para conter ref
ou out
argumentos.The argument_list of an element_access is not allowed to contain ref
or out
arguments.
Uma element_access é vinculada dinamicamente (associação dinâmica) se pelo menos uma das seguintes isenções:An element_access is dynamically bound (Dynamic binding) if at least one of the following holds:
- O primary_no_array_creation_expression tem tipo de tempo de compilação
dynamic
.The primary_no_array_creation_expression has compile-time typedynamic
. - Pelo menos uma expressão da argument_list tem 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 typedynamic
and the primary_no_array_creation_expression does not have an array type.
Nesse caso, o compilador classifica o 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 da element_access são então aplicadas em tempo de execução, usando o tipo de tempo de execução em vez do tipo de tempo de compilação das expressões primary_no_array_creation_expression e argument_list 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 tiver o tipo de tempo de compilação dynamic
, o acesso ao elemento passará por uma verificação de tempo de compilação limitada, conforme descrito em verificação de tempo de compilação da resolução dinâmica 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 a primary_no_array_creation_expression de um element_access for um valor de um array_type, o element_access será um acesso à matriz (acesso à 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 tenha um ou mais membros do indexador; nesse caso, a element_access é um acesso do indexador (acesso ao 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 um acesso de matriz, o primary_no_array_creation_expression do 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 um acesso à matriz não tem permissão para conter argumentos nomeados. O número de expressões na argument_list deve ser igual à classificação da array_type, e cada expressão deve ser do tipo int
,,, uint
long
ulong
ou deve ser conversível implicitamente em 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 pelo (s) valor (es) das expressões no 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 em tempo de execução de um acesso de matriz do formulário P[A]
, em que P
é uma primary_no_array_creation_expression de um array_type e A
é um argument_list, consiste nas 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 causar uma exceção, nenhuma etapa adicional será executada.If this evaluation causes an exception, no further steps are executed.- As expressões de índice da argument_list são avaliadas 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) para um dos seguintes tipos é executada
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 nesta 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 for do tiposhort
, uma conversão implícita emint
será executada, já que conversões implícitas deshort
paraint
e de parashort
long
são possíveis.For instance, if the index expression is of typeshort
then an implicit conversion toint
is performed, since implicit conversions fromshort
toint
and fromshort
tolong
are possible. Se a avaliação de uma expressão de índice ou a conversão implícita subsequente causar uma exceção, não serão avaliadas outras expressões de índice e nenhuma etapa adicional será executada.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 ofP
is checked to be valid. Se o valor deP
fornull
, umSystem.NullReferenceException
será lançado e nenhuma etapa adicional será executada.If the value ofP
isnull
, aSystem.NullReferenceException
is thrown and no further steps are executed. - O valor de cada expressão na argument_list é verificado em relação aos 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 byP
. Se um ou mais valores estiverem fora do intervalo, umSystem.IndexOutOfRangeException
será lançado e nenhuma etapa adicional será executada.If one or more values are out of range, aSystem.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 torna o resultado do acesso à 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 um acesso de indexador, o primary_no_array_creation_expression do element_access deve ser uma variável ou um valor de uma classe, struct ou tipo de interface, e esse tipo deve implementar um ou mais indexadores que são aplicáveis em relação ao argument_list do 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 vinculação de um acesso de indexador do formulário P[A]
, em que P
é uma primary_no_array_creation_expression de uma classe, estrutura ou tipo de interface T
, e A
é um argument_list, consiste nas 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 fornecido pelo
T
é construído.The set of indexers provided byT
is constructed. O conjunto consiste em todos os indexadores declarados emT
ou em um tipo baseT
que não sãooverride
declarações e que são acessíveis no contexto atual (acesso de membro).The set consists of all indexers declared inT
or a base type ofT
that are notoverride
declarations and are accessible in the current context (Member access). - O conjunto é reduzido para os indexadores 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 regras a seguir são aplicadas a cada indexador
S.I
no conjunto, em queS
é o tipo no qual o indexadorI
é declarado:The following rules are applied to each indexerS.I
in the set, whereS
is the type in which the indexerI
is declared:- Se
I
não for aplicável em relação aoA
(membro da função aplicável),I
será removido do conjunto.IfI
is not applicable with respect toA
(Applicable function member), thenI
is removed from the set. - Se
I
for aplicável em relação aoA
(membro de função aplicável), todos os indexadores declarados em um tipo base deS
serão removidos do conjunto.IfI
is applicable with respect toA
(Applicable function member), then all indexers declared in a base type ofS
are removed from the set. - Se
I
for aplicável em relação aoA
(membro de função aplicável) eS
for um tipo de classe diferente deobject
, todos os indexadores declarados em uma interface serão removidos do conjunto.IfI
is applicable with respect toA
(Applicable function member) andS
is a class type other thanobject
, all indexers declared in an interface are removed from the set.
- Se
- Se o conjunto resultante de indexadores candidatos estiver vazio, não existirá nenhum indexador aplicável e ocorrerá um erro de tempo de ligação.If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
- O melhor indexador do conjunto de indexadores candidatos é identificado usando as regras de resolução de sobrecarga da 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 melhor indexador não puder ser identificado, o acesso ao indexador será ambíguo e ocorrerá um erro de tempo de ligaçã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 da argument_list são avaliadas 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 do acesso ao indexador é uma expressão classificada como um acesso de indexador.The result of processing the indexer access is an expression classified as an indexer access. A expressão de acesso do indexador faz referência ao indexador determinado na etapa acima e tem uma expressão de instância associada
P
e uma lista de argumentos associados deA
.The indexer access expression references the indexer determined in the step above, and has an associated instance expression ofP
and an associated argument list ofA
.
Dependendo do contexto no qual ele é usado, um acesso ao indexador causa a invocação do acessador get ou do 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 for o destino de uma atribuição, o acessador set será invocado 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 é invocado para obter o valor atual (valores de expressões).In all other cases, the get accessor is invoked to obtain the current value (Values of expressions).
Este acessoThis access
Uma this_access consiste na palavra reservada this
.A this_access consists of the reserved word this
.
this_access
: 'this'
;
Um this_access é permitido apenas no 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.Whenthis
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 dentro da qual o uso ocorre 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 um primary_expression dentro de um método de instância ou acessador de instância de uma classe, ele é classificado como um valor.Whenthis
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 dentro da qual o uso ocorre e o valor é uma referência ao objeto para o qual o método ou 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 uma struct, ele é classificado como uma variável.Whenthis
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) da estrutura dentro da qual o uso ocorre 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. Athis
variável de um construtor de instância de um struct se comporta exatamente como umout
parâmetro do tipo struct — em particular, isso significa que a variável deve ser definitivamente atribuída em cada caminho de execução do construtor da instância.Thethis
variable of an instance constructor of a struct behaves exactly the same as anout
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 um primary_expression dentro de um método de instância ou acessador de instância de uma struct, ele é classificado como uma variável.Whenthis
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) da estrutura na qual o uso ocorre.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 acessador não for um iterador (iteradores), a
this
variável representará a estrutura para a qual o método ou acessador foi invocado e se comlatará exatamente como umref
parâmetro do tipo struct.If the method or accessor is not an iterator (Iterators), thethis
variable represents the struct for which the method or accessor was invoked, and behaves exactly the same as aref
parameter of the struct type. - Se o método ou o acessador for um iterador, a
this
variável representará uma cópia da estrutura para a qual o método ou acessador foi invocado e se comlatará exatamente como um parâmetro de valor do tipo struct.If the method or accessor is an iterator, thethis
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.
- Se o método ou acessador não for um iterador (iteradores), a
O 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 referir-se a um this
método estático, um acessador de propriedade estática ou em uma 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
Uma base_access consiste na 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 ']'
;
Uma base_access é usada para acessar membros da classe base que são ocultados por membros nomeados de forma semelhante na classe ou struct atual.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 apenas no 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
o 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.
No momento da associação, base_access expressões do formulário base.I
e base[E]
são avaliadas exatamente como se elas fossem gravadas ((B)this).I
e ((B)this)[E]
, em que B
é a classe base da classe ou struct na qual a construção ocorre.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. Assim, base.I
e base[E]
correspondem a this.I
e this[E]
, exceto pelo, this
é exibido 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 referencia um membro de função virtual (um método, uma propriedade ou um indexador), a determinação de qual membro de função invocar em tempo de execução (verificação de tempo de compilação da resolução dinâmica de sobrecarga) é alterada.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 invocado é determinado pela localização da implementação mais derivada (métodos virtuais) do membro da função em relação a B
(em vez de em relação ao tipo de tempo de execução de this
, como seria usual em um acesso não-base).The function member that is invoked is determined by finding the most derived implementation (Virtual methods) of the function member with respect to B
(instead of with respect to the run-time type of this
, as would be usual in a non-base access). Portanto, dentro override
de um de um virtual
membro de função, um base_access pode ser usado para invocar 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 for abstract, ocorrerá um erro de 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 de sufixo ou uma operação de decréscimo deve ser uma expressão classificada como uma variável, um acesso de propriedade ou um acesso de 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 que o operando.The result of the operation is a value of the same type as the operand.
Se o primary_expression tiver o tipo de tempo de compilação dynamic
, o operador será vinculado dinamicamente (associação dinâmica), o post_increment_expression ou post_decrement_expression tem o tipo de tempo dynamic
de compilação e as regras a seguir 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 incremento de sufixo ou uma operação de decréscimo for um acesso de propriedade ou indexador, a propriedade ou o indexador deverá ter um 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 esse não for o caso, ocorrerá um erro de tempo de associaçã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) é aplicada para selecionar uma implementação de operador específica.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. ++
Os operadores e predefinidos --
existem para os seguintes tipos:,,,,,,,, sbyte
,, byte
short
ushort
int
uint
long
ulong
char
float
double
, decimal
e 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. Os operadores predefinidos ++
retornam o valor produzido pela adição de 1 ao operando, e os operadores predefinidos --
retornam o valor produzido pela subtração de 1 do 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 estiver fora do intervalo do tipo de resultado e o tipo de resultado for um tipo integral ou tipo de enumeração, um System.OverflowException
será gerado.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 em tempo de execução de um incremento de sufixo ou uma operação de diminuição do formulário x++
ou x--
consiste nas 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:Ifx
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 ofx
is saved. - O operador selecionado é invocado com o valor salvo
x
como seu argumento.The selected operator is invoked with the saved value ofx
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 ofx
. - O valor salvo de
x
se torna o resultado da operação.The saved value ofx
becomes the result of the operation.
- Se
x
é classificado como um acesso de propriedade ou indexador:Ifx
is classified as a property or indexer access:- A expressão de instância (se
x
não forstatic
) e a lista de argumentos (sex
for um acesso de indexador) associada ax
são avaliadas e os resultados são usados nasget
invocações subsequentes eset
acessadores.The instance expression (ifx
is notstatic
) and the argument list (ifx
is an indexer access) associated withx
are evaluated, and the results are used in the subsequentget
andset
accessor invocations. - O
get
acessador dox
é invocado e o valor retornado é salvo.Theget
accessor ofx
is invoked and the returned value is saved. - O operador selecionado é invocado com o valor salvo
x
como seu argumento.The selected operator is invoked with the saved value ofx
as its argument. - O
set
acessador dex
é invocado com o valor retornado pelo operador como seuvalue
argumento.Theset
accessor ofx
is invoked with the value returned by the operator as itsvalue
argument. - O valor salvo de
x
se torna o resultado da operação.The saved value ofx
becomes the result of the operation.
- A expressão de instância (se
Os ++
--
operadores e também dão suporte à notação de prefixo (operadores de incremento e diminuição de prefixo).The ++
and --
operators also support prefix notation (Prefix increment and decrement operators). Normalmente, o resultado de x++
ou x--
é o valor de x
antes da operação, enquanto o resultado de ++x
ou --x
é o valor de 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
ele tem o mesmo valor após a operação.In either case, x
itself has the same value after the operation.
Uma operator ++
operator --
implementação ou pode ser chamada usando o sufixo ou a notação de prefixo.An operator ++
or operator --
implementation can be invoked using either postfix or prefix notation. Não é possível ter implementações de operador separadas 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:
- As expressões de criação de objeto são usadas para criar novas instâncias de tipos de classe e tipos de valor.Object creation expressions are used to create new instances of class types and value types.
- As expressões de criação de matriz são usadas para criar novas instâncias de tipos de matriz.Array creation expressions are used to create new instances of array types.
- As expressões de criação de representante são usadas para criar novas instâncias de tipos delegados.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 a alocação dinâmica da memória.The new
operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. Em particular, as instâncias de tipos de valor não exigem memória adicional além das variáveis em que residem, e nenhuma alocação dinâmica ocorre quando new
é usada 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
Um object_creation_expression é usado para criar uma nova instância de um class_type ou um 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 um object_creation_expression deve ser um class_type, um value_type ou um 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.
O argument_list opcional (listas de argumentos) só será permitido se o tipo for um class_type ou um struct_type.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 do construtor e os parênteses delimitadores fornecidos incluem um inicializador de objeto ou 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 do construtor e parênteses delimitadores é equivalente a especificar uma lista de argumentos vazia.Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.
O processamento de uma expressão de criação de objeto que inclui um inicializador de objeto ou inicializador de coleção consiste no primeiro processamento do construtor de instância e no processamento das inicializações de membro ou elemento especificadas pelo inicializador de objeto (inicializadores de objeto) ou pelo 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 no argument_list opcional tiver o tipo de tempo de compilação dynamic
, a object_creation_expression será vinculada dinamicamente (associação dinâmica) e as regras a seguir serão aplicadas em tempo de execução usando o tipo de tempo de execução desses argumentos da 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 passa por uma verificação de tempo de compilação limitada, conforme descrito em verificação de tempo de compilação da resolução dinâmica de sobrecarga.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)
, em que T
é um class_type ou um value_type e A
é um argument_list opcional, consiste nas 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 eA
não está presente:IfT
is a value_type andA
is not present:- O object_creation_expression é uma invocação de construtor padrão.The object_creation_expression is a default constructor invocation. O resultado da object_creation_expression é um valor do tipo, ou seja
T
, o valor padrão para,T
conforme definido no tipo System. ValueType.The result of the object_creation_expression is a value of typeT
, namely the default value forT
as defined in The System.ValueType type.
- O object_creation_expression é uma invocação de construtor padrão.The object_creation_expression is a default constructor invocation. O resultado da object_creation_expression é um valor do tipo, ou seja
- Caso contrário, se
T
for um type_parameter eA
não estiver presente:Otherwise, ifT
is a type_parameter andA
is not present:- Se nenhuma restrição de tipo de valor ou restrição de Construtor (restrições de parâmetro de tipo) tiver sido especificada para
T
, ocorrerá um erro de tempo de associação.If no value type constraint or constructor constraint (Type parameter constraints) has been specified forT
, a binding-time error occurs. - O resultado da object_creation_expression é um valor do tipo de tempo de execução ao qual o parâmetro de tipo foi associado, ou seja, o resultado da invocação do 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.
- Se nenhuma restrição de tipo de valor ou restrição de Construtor (restrições de parâmetro de tipo) tiver sido especificada para
- Caso contrário, se
T
for um class_type ou um struct_type:Otherwise, ifT
is a class_type or a struct_type:- Se
T
for umabstract
class_type, ocorrerá um erro em tempo de compilação.IfT
is anabstract
class_type, a compile-time error occurs. - O construtor de instância a ser invocado é determinado usando as regras de resolução de sobrecarga da 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 candidata consiste em todos os construtores de instância acessíveis declarados no
T
que são aplicáveis em relação aA
(membro de função aplicável).The set of candidate instance constructors consists of all accessible instance constructors declared inT
which are applicable with respect toA
(Applicable function member). Se o conjunto de construtores de instância de candidato estiver vazio, ou se um único Construtor de instância recomendada não puder 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 da object_creation_expression é um valor do tipo, ou seja
T
, o valor produzido por invocar o construtor da instância determinado na etapa acima.The result of the object_creation_expression is a value of typeT
, namely the value produced by invoking the instance constructor determined in the step above.
- Se
- Caso contrário, o object_creation_expression é inválido e ocorre um erro de tempo de ligação.Otherwise, the object_creation_expression is invalid, and a binding-time error occurs.
Mesmo que a object_creation_expression seja vinculada dinamicamente, o tipo de tempo de compilação ainda será T
.Even if the object_creation_expression is dynamically bound, the compile-time type is still T
.
O processamento em tempo de execução de um object_creation_expression do formulário new T(A)
, em que T
é class_type ou uma struct_type e A
é um argument_list opcional, consiste nas 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:IfT
is a class_type:- Uma nova instância da classe
T
é alocada.A new instance of classT
is allocated. Se não houver memória suficiente disponível para alocar a nova instância, umSystem.OutOfMemoryException
será lançado e nenhuma etapa adicional será executada.If there is not enough memory available to allocate the new instance, aSystem.OutOfMemoryException
is thrown and no further steps are executed. - Todos os campos da nova instância são inicializados para 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 de invocação de membro de função (verificação de tempo de compilação da resolução dinâmica de sobrecarga).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 alocada recentemente é passada automaticamente 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 asthis
.
- Uma nova instância da classe
- Se
T
é um struct_type:IfT
is a struct_type:- Uma instância do tipo
T
é criada alocando-se uma variável local temporária.An instance of typeT
is created by allocating a temporary local variable. Como um construtor de instância de um struct_type é necessário para atribuir definitivamente um valor a cada campo da instância que está sendo criada, 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 de invocação de membro de função (verificação de tempo de compilação da resolução dinâmica de sobrecarga).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 alocada recentemente é passada automaticamente 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 asthis
.
- Uma instância do tipo
Inicializadores de objetoObject initializers
Um 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, entre os {
}
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. Um identificador deve nomear um campo ou Propriedade acessível do objeto que está sendo inicializado, enquanto um argument_list 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 é seguida 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 que as expressões no inicializador de objeto façam 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 após 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 ao campo ou à propriedade, as atribuições no inicializador de objeto aninhado são tratadas como atribuições para membros do campo ou da 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 aninhados 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 ao campo de destino, à propriedade ou ao 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 satisfaça os 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 acabarem nunca sendo usados (por exemplo, devido a um inicializador aninhado vazio), eles serão avaliados para 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 do Point
pode ser criada e inicializada 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;
em que __a
é uma variável temporária 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 do Rectangle
pode ser criada e inicializada 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;
onde __r
__p1
e __p2
são variáveis temporárias que, de outra forma, são invisíveis e inacessíveis.where __r
, __p1
and __p2
are temporary variables that are otherwise invisible and inaccessible.
Rectangle
O Construtor If aloca as duas instâncias inseridas Point
If 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 as Point
instâncias inseridas 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 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: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;
em que __c
, etc., são variáveis geradas 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 avaliados apenas uma vez, e os argumentos para [1,2]
são avaliados uma vez, mesmo que nunca sejam 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 os {
}
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 os {
}
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 uma única expressão pode ser gravado sem chaves, mas não pode ser uma expressão de atribuição para evitar ambigüidade 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. A produção non_assignment_expression é definida na expressão.The non_assignment_expression production is defined in Expression.
Veja a seguir 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 em 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 especificado na ordem, o inicializador de coleção invoca um Add
método no objeto de destino com a lista de expressões do inicializador de elemento como lista de argumentos, aplicando a resolução de membro normal e a solução de sobrecarga para cada invocação.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 uma instância aplicável ou um método de extensão 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;
onde __clist
__c1
e __c2
são variáveis temporárias que, de outra forma, são 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
Um 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 resulta 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 de expressões deve ser do tipo int
, uint
, long
ou ulong
, ou conversível implicitamente 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 alocada recentemente.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, é um erro de tempo de compilação ter um 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 não seguro (contextos não seguros), o layout das 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 incluir um inicializador de matriz, cada expressão na lista de expressões deverá ser uma constante e os comprimentos de classificação e de dimensão especificados pela lista de expressões devem corresponder àqueles 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 do segundo ou terceiro formulário, a classificação do tipo de matriz ou especificador de classificação 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. Portanto, a expressãoThus, the expression
new int[,] {{0, 1}, {2, 3}, {4, 5}}
corresponde exatamente aexactly 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 uma *expressão de criação de matriz digitada implicitamente.An array creation expression of the third form is referred to as an *implicitly typed array creation expression _. Ele é semelhante ao segundo formulário, exceto pelo fato de que o tipo de elemento da matriz não é fornecido explicitamente, mas determinado como o melhor tipo comum (encontrando o melhor tipo comum de um conjunto de expressões) do conjunto de expressões no inicializador de matriz.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, uma em que o _rank_specifier * contém pelo menos uma vírgula, esse conjunto inclui todas as expressões s encontradas em array_initializer s aninhadas.For a multidimensional array, i.e., one where the _rank_specifier* contains at least one comma, this set comprises all expression s found in nested array_initializer s.
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 à instância de matriz alocada recentemente.The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. O processamento em tempo de execução de uma expressão de criação de matriz consiste nas seguintes etapas:The run-time processing of an array creation expression consists of the following steps:
- As expressões de comprimento da dimensão da expression_list são avaliadas 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) para um dos seguintes tipos é executada:
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 nesta 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 causar uma exceção, nenhuma expressão adicional será avaliada e nenhuma outra etapa será 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 comprimentos das dimensões são validados da seguinte maneira.The computed values for the dimension lengths are validated as follows. Se um ou mais valores forem menores que zero, um
System.OverflowException
será lançado e nenhuma etapa adicional será executada.If one or more of the values are less than zero, aSystem.OverflowException
is thrown and no further steps are executed. - Uma instância de matriz com os tamanhos de dimensão fornecidos é 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
será lançado e nenhuma etapa adicional será executada.If there is not enough memory available to allocate the new instance, aSystem.OutOfMemoryException
is thrown and no further steps are executed. - Todos os elementos da nova instância de matriz são inicializados para 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 no inicializador de matriz será avaliada e atribuída ao elemento de matriz correspondente.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 avaliações e as atribuiçõ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 ordem de índice crescente, com a dimensão mais à direita aumentando primeiro.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 a atribuição subsequente ao elemento de matriz correspondente causar uma exceção, nenhum elemento adicional será inicializado (e os elementos restantes terão, portanto, 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 instanciação de uma matriz com elementos de um tipo de matriz, mas os elementos de tal 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 que a mesma expressão de criação de matriz também instancie as 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
resulta em um erro de tempo de compilação.results in a compile-time error. Em vez disso, a instanciação das submatrizes 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 uma forma "retangular", ou seja, quando as submatrizes têm o 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 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.
Veja a seguir exemplos de expressões de criação de matriz digitadas implicitamente: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 a outra e, portanto, não há um melhor tipo 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 neste 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 base comum, que se tornaria o tipo de elemento inferido.Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.
As expressões de criação de matriz com tipo implícito podem ser combinadas com inicializadores de objeto anônimo (expressões de criação de objeto anônimo) para criar estruturas de dados com tipo anônimo.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" }
}
};
Delegar expressões de criaçãoDelegate creation expressions
Uma delegate_creation_expression é usada 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étodos, uma função anônima ou um valor do 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 identificará 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, ele definirá diretamente os parâmetros e o corpo do método do destino 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, ele identificará uma instância de delegado da qual criar uma cópia.If the argument is a value it identifies a delegate instance of which to create a copy.
Se a expressão tiver o tipo de tempo de compilação dynamic
, a delegate_creation_expression será vinculada dinamicamente (associação dinâmica) e as regras abaixo serão aplicadas em tempo de execução usando o tipo de tempo de execução da 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)
, em que D
é uma delegate_type e E
é uma expressão, consiste nas 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
for um grupo de métodos, a expressão de criação de representante será processada da mesma maneira que uma conversão de grupo de métodos (conversões de grupos de métodos) deE
paraD
.IfE
is a method group, the delegate creation expression is processed in the same way as a method group conversion (Method group conversions) fromE
toD
. - Se
E
for uma função anônima, a expressão de criação de delegado será processada da mesma maneira que uma conversão de função anônima (conversões de função anônimas) deE
paraD
.IfE
is an anonymous function, the delegate creation expression is processed in the same way as an anonymous function conversion (Anonymous function conversions) fromE
toD
. - Se
E
for um valor,E
deve ser compatível (delegar declarações) comD
, e o resultado é uma referência a um delegado recém-criado do tipoD
que se refere à mesma lista de invocação que oE
.IfE
is a value,E
must be compatible (Delegate declarations) withD
, and the result is a reference to a newly created delegate of typeD
that refers to the same invocation list asE
. SeE
não for compatível comD
, ocorrerá um erro em tempo de compilação.IfE
is not compatible withD
, a compile-time error occurs.
O processamento em tempo de execução de uma delegate_creation_expression do formulário new D(E)
, em que D
é uma delegate_type e E
é uma expressão, consiste nas 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
for um grupo de métodos, a expressão de criação de representante será avaliada como uma conversão de grupo de métodos (conversões de grupos de métodos) deE
paraD
.IfE
is a method group, the delegate creation expression is evaluated as a method group conversion (Method group conversions) fromE
toD
. - Se
E
for uma função anônima, a criação de delegado será avaliada como uma conversão de função anônima deE
paraD
(conversões de função anônimas).IfE
is an anonymous function, the delegate creation is evaluated as an anonymous function conversion fromE
toD
(Anonymous function conversions). - Se
E
é um valor de uma delegate_type:IfE
is a value of a delegate_type:E
é avaliado.E
is evaluated. Se essa avaliação causar uma exceção, nenhuma etapa adicional será executada.If this evaluation causes an exception, no further steps are executed.- Se o valor de
E
fornull
, umSystem.NullReferenceException
será lançado e nenhuma etapa adicional será executada.If the value ofE
isnull
, aSystem.NullReferenceException
is thrown and no further steps are executed. - Uma nova instância do tipo delegado
D
é alocada.A new instance of the delegate typeD
is allocated. Se não houver memória suficiente disponível para alocar a nova instância, umSystem.OutOfMemoryException
será lançado e nenhuma etapa adicional será executada.If there is not enough memory available to allocate the new instance, aSystem.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 de delegado fornecida pelo
E
.The new delegate instance is initialized with the same invocation list as the delegate instance given byE
.
A lista de invocação de um delegado é determinada quando o delegado é instanciado e, em seguida, permanece constante para todo o tempo de vida 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 podem ser chamadas de um delegado depois que ele tiver 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 é removido de outro (delegar declarações), um novo delegado resulta; 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 se refere 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 a partir de um grupo de métodos, a lista de parâmetros formais e o tipo de retorno do delegado determinam qual dos métodos sobrecarregados 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 ao segundo Square
método porque esse método corresponde exatamente à lista de parâmetros formais e ao 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
. Se o segundo Square
método não estiver presente, ocorreria um erro em tempo de compilação.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
Um 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ônimo 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 de classe sem nome que herda diretamente do 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 inferidas 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() { ... }
}
onde 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 um 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 um member_declarator ser nulo 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 que a expressão tenha um tipo 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 para seu Equals
método são gerados automaticamente pelo compilador e não podem ser referenciados 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ão 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.
Os Equals
GetHashcode
métodos e em tipos anônimos substituem os métodos herdados de e object
são definidos em termos de Equals
e GetHashcode
das propriedades, de forma que duas instâncias do mesmo tipo anônimo sejam iguais se e somente se todas as suas propriedades forem 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 de tipo), um acesso de membro (verificação de tempo de compilação de resolução dinâmica de sobrecarga), um acesso base (acesso de base) ou um membro condicional nulo de acesso (expressões condicionais nulas 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 inicializador de projeção e é abreviado para uma declaração de e 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 membros dos formuláriosSpecifically, member declarators of the forms
identifier
expr.identifier
são precisamente equivalentes aos seguintes, respectivamente:are precisely equivalent to the following, respectively:
identifier = identifier
identifier = expr.identifier
Portanto, em um inicializador de projeção, o identificador seleciona o valor e o campo ou propriedade ao 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 projeta 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 uma typeof
palavra-chave seguida por um tipo entre parênteses.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 específico.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 uma typeof
palavra-chave seguida por uma unbound_type_name entre parênteses.The second form of typeof_expression consists of a typeof
keyword followed by a parenthesized unbound_type_name. Um unbound_type_name é muito semelhante a um type_name (namespace e nomes de tipo), exceto pelo fato de que um unbound_type_name contém generic_dimension_specifier s onde um type_name contém type_argument_list s.An unbound_type_name is very similar to a type_name (Namespace and type names) except that an unbound_type_name contains generic_dimension_specifier s where a type_name contains type_argument_list s. Quando o operando de uma typeof_expression é uma sequência de tokens que satisfaz as gramáticas de unbound_type_name e type_name, ou seja, quando ele não contém uma generic_dimension_specifier nem uma type_argument_list, a sequência de tokens é considerada uma 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:
- Converta a sequência de tokens em um type_name substituindo cada generic_dimension_specifier por uma type_argument_list com o mesmo número de vírgulas e a palavra-chave
object
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 keywordobject
as each type_argument. - Avalie as type_name resultantes, 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 é resolvido para o tipo genérico não associado associado ao tipo construído resultante (tipos vinculados e desvinculados).The unbound_type_name resolves to the unbound generic type associated with the resulting constructed type (Bound and unbound types).
O resultado da typeof_expression é o System.Type
objeto para o tipo genérico não associado resultante.The result of the typeof_expression is the System.Type
object for the resulting unbound generic type.
A terceira forma de typeof_expression consiste em uma typeof
palavra-chave seguida por uma void
palavra-chave entre parênteses.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 de tipo retornado por typeof(void)
é diferente do objeto de tipo 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 a reflexão em métodos no idioma, em que esses métodos desejam ter uma maneira 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 foi 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 (tipos vinculados e desvinculados).The typeof
operator can also be used on a constructed type or an unbound generic type (Bound and unbound types). O System.Type
objeto para um tipo genérico não associado não é o mesmo que o 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 que seu System.Type
objeto dependa dos argumentos de tipo de tempo de execução em uso, enquanto o tipo genérico não associado não tem argumentos 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 não typeof(X<>)
depende do argumento de tipo, mas o resultado de typeof(X<T>)
.Also note that the result of typeof(X<>)
does not depend on the type argument but the result of typeof(X<T>)
does.
Os operadores verificados e não verificadosThe checked and unchecked operators
Os checked
unchecked
operadores e são usados para controlar o contexto de verificação de estouro para operações e conversõ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 selecionado 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 a um parenthesized_expression (expressões entre parênteses), exceto que a expressão contida é avaliada no contexto de verificação de estouro especificado.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 das checked
unchecked
instruções e (as instruções marcadas e não verificadas).The overflow checking context can also be controlled through the checked
and unchecked
statements (The checked and unchecked statements).
As operações a seguir são afetadas pelo contexto de verificação de estouro estabelecido pelos checked
unchecked
operadores e instruções:The following operations are affected by the overflow checking context established by the checked
and unchecked
operators and statements:
- Os operadores predefinidos
++
e--
unários (incremento de sufixo e decremento e operadores de incremento e diminuição de prefixo) quando o operando é de um tipo integral.The predefined++
and--
unary operators (Postfix increment and decrement operators and Prefix increment and decrement operators), when the operand is of an integral type. - O
-
operador unário predefinido (operador menos unário), quando o operando é de um tipo integral.The predefined-
unary operator (Unary minus operator), when the operand is of an integral type. - Os operadores predefinidos
+
,-
,*
e/
binários (operadores aritméticos), quando ambos os operandos são de tipos integrais.The predefined+
,-
,*
, and/
binary operators (Arithmetic operators), when both operands are of integral types. - Conversões numéricas explícitas (conversões numéricas explícitas) de um tipo integral para outro tipo integral ou de
float
oudouble
para um tipo integral.Explicit numeric conversions (Explicit numeric conversions) from one integral type to another integral type, or fromfloat
ordouble
to an integral type.
Quando uma das operações acima produz um resultado muito grande para representar no tipo de destino, o contexto no qual a operação é executada controla 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 constante (expressões constantes), ocorrerá um erro em tempo de compilação.In achecked
context, if the operation is a constant expression (Constant expressions), a compile-time error occurs. Caso contrário, quando a operação for executada em tempo de execução, umSystem.OverflowException
será gerado.Otherwise, when the operation is performed at run-time, aSystem.OverflowException
is thrown. - Em um
unchecked
contexto, o resultado é truncado descartando quaisquer bits de ordem superior que não caibam no tipo de destino.In anunchecked
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 que são avaliadas em tempo de execução) que não são delimitadas checked
por unchecked
operadores ou instruções or, o contexto de verificação de estouro padrão é unchecked
a menos que fatores externos (como comutadores de compilador e configuração de ambiente de execução) chamem 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 constantes (expressões que podem ser totalmente avaliadas em tempo de compilação), o contexto de verificação de estouro 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 constante seja colocada explicitamente em um unchecked
contexto, os estouros que ocorrerem durante a avaliação do tempo de compilação da expressão sempre causarão 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 por 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
}
}
Não são relatados erros de tempo de compilação, 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 gera um System.OverflowException
e o G
método retorna-727379968 (os bits inferiores de 32 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 de verificação de estouro padrão para a compilação, mas é o mesmo 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 que ocorrem ao avaliar as expressões constantes no F
e H
causam erros de tempo de compilação a serem relatados 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 constante no G
, mas como a avaliação ocorre em um unchecked
contexto, o estouro não é 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.
Os checked
unchecked
operadores e afetam apenas o contexto de verificação de estouro para as operações que estão contextualmente contidas nos (
tokens "" e "" )
.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 nenhum efeito nos membros da função que são invocados como resultado da avaliação da expressão contida.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
no F
não afeta a avaliação de x * y
no Multiply
, portanto x * y
é avaliado no contexto de verificação de estouro 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 assinados 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 estão fora do int
intervalo, sem o unchecked
operador, as conversões para int
produzir erros em 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.
Os checked
unchecked
operadores e e instruções permitem que os programadores controlem 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 dos tipos de dados dos operandos.However, the behavior of some numeric operators depends on their operands' data types. Por exemplo, multiplicar dois decimais sempre resulta em uma exceção no estouro, mesmo dentro de um unchecked
constructo explicitamente.For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked
construct. Da mesma forma, multiplicar dois floats nunca resulta em uma exceção no estouro, mesmo em um checked
constructo explicitamente.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, sejam eles padrão ou explícitos.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, pois ela poderá não ser conhecida se o parâmetro de tipo for um tipo de valor ou 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. (Nenhuma conversão existe do null
literal para um parâmetro de tipo, a menos que o parâmetro de tipo seja conhecido como 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 for avaliado em tempo de execução para um tipo de referência, o resultado será 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 for avaliado em tempo de execução para um tipo de valor, o resultado será o valor padrão do value_type(construtores padrão).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).
Uma default_value_expression é uma expressão constante (expressões constantes) se o tipo é um tipo de referência ou um parâmetro de tipo que é conhecido como um tipo de referência (restrições de parâmetro de tipo).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, um default_value_expression é uma expressão constante se o tipo for um dos tipos de valor a seguir:,,,,, 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 de 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
;
Em termos de gramática, o operando named_entity sempre é uma expressão.Grammatically speaking, the named_entity operand is always an expression. Como nameof
não é uma palavra-chave reservada, uma expressão nameof é sempre sintaticamente ambígua com uma invocação do nome simples nameof
.Because nameof
is not a reserved keyword, a nameof expression is always syntactically ambiguous with an invocation of the simple name nameof
. Por motivos de compatibilidade, se uma pesquisa de nome (nomes simples) do nome nameof
for bem sucedido, a expressão será tratada como um invocation_expression , independentemente de a invocação ser legal ou não.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, é um nameof_expression.Otherwise it is a nameof_expression.
O significado da named_entity de uma nameof_expression é o significado dela como uma expressão; ou seja, 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, onde a pesquisa descrita em nomes simples e acesso de membro resulta em um erro porque um membro de instância foi encontrado em um contexto estático, um nameof_expression não produz 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 ter o tipo dynamic
.It is a compile time error for a named_entity_target to have the type dynamic
.
Uma nameof_expression é uma expressão constante do tipo string
e não tem nenhum efeito no 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 é 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 da named_entity antes da type_argument_list final opcional, 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, será removido.The prefix "@
", if used, is removed. - Cada unicode_escape_sequence é transformada em seu caractere Unicode correspondente.Each unicode_escape_sequence is transformed into its corresponding Unicode character.
- Todas as formatting_characters são removidas.Any formatting_characters are removed.
Essas são as mesmas transformações aplicadas em 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. Eles são descritos mais detalhadamente em expressões de função anônimas.These are further described in Anonymous function expressions.
Operadores unáriosUnary operators
Os ?
operadores,,,,,, +
-
!
~
++
--
, CAST e await
são chamados de operadores unários.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 tiver o tipo de tempo de compilação dynamic
, ele será vinculado dinamicamente (associaçã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 tipo de tempo de compilação do unary_expression é dynamic
, e a resolução descrita abaixo 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 condicional nuloNull-conditional operator
O operador NULL-Conditional aplica uma lista de operações ao operando somente se esse 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 a membros e operações de acesso de elemento (que podem ser nulas-condicionais), 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()
é uma null_conditional_expression com um primary_expression a.b
e null_conditional_operations ?[0]
(acesso de elemento condicional nulo), ?.c
(acesso de membro condicional nulo) 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
, vamos E0
ser a expressão obtida com a remoção textual da entrelinha de ?
cada uma das null_conditional_operations delas E
.For a null_conditional_expression E
with a primary_expression P
, let E0
be the expression obtained by textually removing the leading ?
from each of the null_conditional_operations of E
that have one. Conceitualmente, E0
é a expressão que será avaliada se nenhuma das verificações nulas representadas por ?
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, vamos E1
ser a expressão obtida por meio da remoção textual da entrelinha ?
apenas da primeira das 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 uma expressão primária (se houver apenas uma ?
) ou a outra 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
for a expressão a.b?[0]?.c()
, E0
será a expressão a.b[0].c()
e E1
será 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
for classificado como Nothing, E
será classificado como Nothing.If E0
is classified as nothing, then E
is classified as nothing. Caso contrário, E será 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
ocorrer como um statement_expression o significado deE
é o mesmo que a instruçãoIfE
occurs as a statement_expression the meaning ofE
is the same as the statementif ((object)P != null) E1;
Exceto que P é avaliada apenas uma vez.except that P is evaluated only once.
Caso contrário, se
E0
for classificado como nada ocorrerá um erro de tempo de compilação.Otherwise, ifE0
is classified as nothing a compile-time error occurs.Caso contrário, permita que
T0
seja o tipo deE0
.Otherwise, letT0
be the type ofE0
.Se
T0
for um parâmetro de tipo que não é conhecido como um tipo de referência ou um tipo de valor não anulável, ocorrerá um erro em tempo de compilação.IfT0
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
for um tipo de valor não anulável, o tipo deE
éT0?
e o significado deE
é o mesmo queIfT0
is a non-nullable value type, then the type ofE
isT0?
, and the meaning ofE
is the same as((object)P == null) ? (T0?)null : E1
Exceto que
P
é avaliado apenas uma vez.except thatP
is evaluated only once.Caso contrário, o tipo de E é T0, e o significado de 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 que
P
é avaliado apenas uma vez.except thatP
is evaluated only once.
Se o E1
próprio for um null_conditional_expression, essas regras serão aplicadas novamente, aninhando os testes para null
até que não haja mais ?
, e a expressão tenha sido reduzida até a expressão primária 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()
ocorrer como uma expressão de instrução, como na 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 avaliados apenas uma vez.Except that a.b
and a.b[0]
are evaluated only once.
Se 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 final não seja 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 avaliados apenas uma vez.except that a.b
and a.b[0]
are evaluated only once.
Expressões condicionais nulas como inicializadores de projeçãoNull-conditional expressions as projection initializers
Uma expressão condicional nula só é permitida como uma member_declarator em uma anonymous_object_creation_expression (expressões de criação de objeto anônimo) se terminar com um acesso de membro (opcionalmente nulo).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. Na gramática, 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?
;
Este é um caso especial da gramática para null_conditional_expression acima.This is a special case of the grammar for null_conditional_expression above. A produção para member_declarator em expressões de criação de objeto anônimo inclui apenas null_conditional_member_access.The production for member_declarator in Anonymous object creation expressions then includes only null_conditional_member_access.
Expressões condicionais nulas como expressões de instruçãoNull-conditional expressions as statement expressions
Uma expressão condicional nula só é permitida como uma statement_expression (instruções de expressão) se terminar com uma invocação.A null-conditional expression is only allowed as a statement_expression (Expression statements) if it ends with an invocation. Na gramática, esse requisito pode ser expresso como:Grammatically, this requirement can be expressed as:
null_conditional_invocation_expression
: primary_expression null_conditional_operations '(' argument_list? ')'
;
Este é um caso especial da gramática para null_conditional_expression acima.This is a special case of the grammar for null_conditional_expression above. A produção para statement_expression em instruções de expressão , em seguida, inclui apenas null_conditional_invocation_expression.The production for statement_expression in Expression statements then includes only null_conditional_invocation_expression.
Operador de adição de unárioUnary plus operator
Para uma operação do formulário +x
, a resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicada para selecionar uma implementação de operador específica.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 é convertido para o tipo de parâmetro do operador selecionado e o tipo de 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 adição de unários predefinidos 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 de subtração de unárioUnary minus operator
Para uma operação do formulário -x
, a resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicada para selecionar uma implementação de operador específica.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 é convertido para o tipo de parâmetro do operador selecionado e o tipo de 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 com a subtração
x
de zero.The result is computed by subtractingx
from zero. Se o valor dex
for o menor valor representável do tipo de operando (-2 ^ 31 paraint
ou-2 ^ 63 paralong
), a negação matemática dex
não será representável dentro do tipo de operando.If the value ofx
is the smallest representable value of the operand type (-2^31 forint
or -2^63 forlong
), then the mathematical negation ofx
is not representable within the operand type. Se isso ocorrer em umchecked
contexto, umSystem.OverflowException
será lançado; se ocorrer dentro de umunchecked
contexto, o resultado será o valor do operando e o estouro não será relatado.If this occurs within achecked
context, aSystem.OverflowException
is thrown; if it occurs within anunchecked
context, the result is the value of the operand and the overflow is not reported.Se o operando do operador de negação for do tipo
uint
, ele será convertido em tipolong
e o tipo do resultado serálong
.If the operand of the negation operator is of typeuint
, it is converted to typelong
, and the type of the result islong
. Uma exceção é a regra que permite que oint
valor-2147483648 (-2 ^ 31) seja gravado como um literal inteiro decimal (literais inteiros).An exception is the rule that permits theint
value -2147483648 (-2^31) to be written as a decimal integer literal (Integer literals).Se o operando do operador de negação for do tipo
ulong
, ocorrerá um erro em tempo de compilação.If the operand of the negation operator is of typeulong
, a compile-time error occurs. Uma exceção é a regra que permite que olong
valor-9.223.372.036.854.775.808 (-2 ^ 63) seja gravado como um literal inteiro decimal (literais inteiros).An exception is the rule that permits thelong
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 seu sinal invertido.The result is the value ofx
with its sign inverted. Sex
for NaN, o resultado também será Nan.Ifx
is NaN, the result is also NaN.Negação decimal:Decimal negation:
decimal operator -(decimal x);
O resultado é calculado com a subtração
x
de zero.The result is computed by subtractingx
from zero. A negação decimal é equivalente a usar o operador de subtração unário do tipoSystem.Decimal
.Decimal negation is equivalent to using the unary minus operator of typeSystem.Decimal
.
Operador de negação lógicaLogical negation operator
Para uma operação do formulário !x
, a resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicada para selecionar uma implementação de operador específica.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 é convertido para o tipo de parâmetro do operador selecionado e o tipo de 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 predefinido:Only one predefined logical negation operator exists:
bool operator !(bool x);
Esse operador computa a negação lógica do operando: se o operando for true
, o resultado será false
.This operator computes the logical negation of the operand: If the operand is true
, the result is false
. Se o operando for false
, o resultado será true
.If the operand is false
, the result is true
.
Operador de complemento bit a bit Bitwise complement operator
Para uma operação do formulário ~x
, a resolução de sobrecarga de operador unário (resolução de sobrecarga de operador unário) é aplicada para selecionar uma implementação de operador específica.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 é convertido para o tipo de parâmetro do operador selecionado e o tipo de 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 predefinidos de Complementos de bits 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 de bits x
.For each of these operators, the result of the operation is the bitwise complement of x
.
Todos os tipos E
de enumeração fornecem implicitamente o seguinte operador de complemento bit a bit:Every enumeration type E
implicitly provides the following bitwise complement operator:
E operator ~(E x);
O resultado da avaliação ~x
, em que x
é uma expressão de um tipo de enumeração E
com um tipo subjacente U
, é exatamente o mesmo que (E)(~(U)x)
a avaliação, exceto que a conversão em E
é sempre executada como se fosse 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 uma operação de incremento ou diminuição de prefixo deve ser uma expressão classificada como uma variável, um acesso de propriedade ou um acesso de 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 que o operando.The result of the operation is a value of the same type as the operand.
Se o operando de uma operação de incremento ou diminuição de prefixo for um acesso de propriedade ou indexador, a propriedade ou o indexador deverá ter um 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 esse não for o caso, ocorrerá um erro de tempo de associaçã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) é aplicada para selecionar uma implementação de operador específica.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. ++
Os operadores e predefinidos --
existem para os seguintes tipos:,,,,,,,, sbyte
,, byte
short
ushort
int
uint
long
ulong
char
float
double
, decimal
e 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. Os operadores predefinidos ++
retornam o valor produzido pela adição de 1 ao operando, e os operadores predefinidos --
retornam o valor produzido pela subtração de 1 do 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 estiver fora do intervalo do tipo de resultado e o tipo de resultado for um tipo integral ou tipo de enumeração, um System.OverflowException
será gerado.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 em tempo de execução de um incremento de prefixo ou uma operação de diminuição do formulário ++x
ou --x
consiste nas 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:Ifx
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 ofx
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 ofx
. - 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:Ifx
is classified as a property or indexer access:- A expressão de instância (se
x
não forstatic
) e a lista de argumentos (sex
for um acesso de indexador) associada ax
são avaliadas e os resultados são usados nasget
invocações subsequentes eset
acessadores.The instance expression (ifx
is notstatic
) and the argument list (ifx
is an indexer access) associated withx
are evaluated, and the results are used in the subsequentget
andset
accessor invocations. - O
get
acessador dox
é invocado.Theget
accessor ofx
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 theget
accessor as its argument. - O
set
acessador dex
é invocado com o valor retornado pelo operador como seuvalue
argumento.Theset
accessor ofx
is invoked with the value returned by the operator as itsvalue
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.
- A expressão de instância (se
Os ++
--
operadores e também dão suporte à notação de sufixo (operadores de aumento de sufixo e diminuição).The ++
and --
operators also support postfix notation (Postfix increment and decrement operators). Normalmente, o resultado de x++
ou x--
é o valor de x
antes da operação, enquanto o resultado de ++x
ou --x
é o valor de 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
ele tem o mesmo valor após a operação.In either case, x
itself has the same value after the operation.
Uma operator++
operator--
implementação ou pode ser chamada usando o sufixo ou a notação de prefixo.An operator++
or operator--
implementation can be invoked using either postfix or prefix notation. Não é possível ter implementações de operador separadas para as duas notações.It is not possible to have separate operator implementations for the two notations.
Expressões castCast expressions
Uma cast_expression é usada para converter explicitamente uma expressão em um determinado tipo.A cast_expression is used to explicitly convert an expression to a given type.
cast_expression
: '(' type ')' unary_expression
;
Uma cast_expression do formulário (T)E
, em que T
é um tipo e E
é um unary_expression, executa uma conversão explícita (conversões explícitas) do valor de E
para tipo 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 não existir nenhuma conversão explícita de E
para T
, ocorrerá um erro de tempo de vinculação.If no explicit conversion exists from E
to T
, a binding-time error occurs. Caso contrário, o resultado será 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
o denota uma variável.The result is always classified as a value, even if E
denotes a variable.
A gramática de um cast_expression leva a determinadas ambiguidades sintáticas.The grammar for a cast_expression leads to certain syntactic ambiguities. Por exemplo, a expressão (x)-y
pode ser interpretada como uma cast_expression (uma conversão de -y
para tipo x
) ou como uma additive_expression combinada com uma parenthesized_expression (que computa 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 as ambiguidades cast_expression , a seguinte regra existe: uma sequência de um ou mais token s (espaço em branco) entre parênteses é considerada o início de uma cast_expression somente se pelo menos uma das seguintes opções for verdadeira:To resolve cast_expression ambiguities, the following rule exists: A sequence of one or more token s (White space) enclosed in parentheses is considered the start of a cast_expression only if at least one of the following are true:
- A sequência de tokens é a gramática correta para um tipo, mas não para uma 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 um 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), um literal (literais) ou qualquer palavra-chave (palavras-chave), excetoas
eis
.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) exceptas
andis
.
O termo "correção gramatical" 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. Ele não considera especificamente o significado real de quaisquer identificadores constituintes.It specifically does not consider the actual meaning of any constituent identifiers. Por exemplo, se x
e y
são identificadores, x.y
é a gramática correta para um tipo, mesmo que, x.y
na verdade, não denotará 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.
A partir da regra de desambiguidade, ela segue, se x
e y
são identificadores,, (x)y
(x)(y)
, e (x)(-y)
são cast_expression s, mas (x)-y
não é, mesmo que x
o identifique um tipo.From the disambiguation rule it follows that, if x
and y
are identifiers, (x)y
, (x)(y)
, and (x)(-y)
are cast_expression s, but (x)-y
is not, even if x
identifies a type. No entanto, se x
for uma palavra-chave que identifica um tipo predefinido (como int
), todas as quatro formas serão cast_expression s (porque essa palavra-chave não poderia ser uma expressão por si só).However, if x
is a keyword that identifies a predefined type (such as int
), then all four forms are cast_expression s (because such a keyword could not possibly be an expression by itself).
Expressões AwaitAwait expressions
O operador Await é usado para suspender a avaliação da função Async delimitadora até que a operação assíncrona representada pelo operando tenha sido 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
;
Um await_expression só é permitido no corpo de uma função Async (funções assíncronas).An await_expression is only allowed in the body of an async function (Async functions). Na função assíncrona delimitadora mais próxima, 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 aninhada (não assíncrona)Inside a nested (non-async) anonymous function
- Dentro do bloco de um lock_statementInside the block of a lock_statement
- Em um contexto sem segurançaIn an unsafe context
Observe que um await_expression não pode ocorrer na maioria dos lugares em um query_expression, pois eles são sintaticamente transformados para usar 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 Async, 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 Await-Expressions e várias expressões que envolvem identificadores.There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. Fora das 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 ser concluída no momento em que o _await_expression * é avaliado.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 Async delimitadora até que a tarefa esperada 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 awaitableAwaitable expressions
A tarefa de uma expressão Await deve ser awaitable.The task of an await expression is required to be awaitable. Uma expressão t
é awaitable se uma das seguintes isenções:An expression t
is awaitable if one of the following holds:
t
é do tipo de tempo de compilaçãodynamic
t
is of compile time typedynamic
t
tem uma instância ou método de extensão acessível chamado semGetAwaiter
parâmetros e nenhum parâmetro de tipo, e um tipo de retornoA
para o qual todos os seguintes itens contêm:t
has an accessible instance or extension method calledGetAwaiter
with no parameters and no type parameters, and a return typeA
for which all of the following hold:A
implementa a interfaceSystem.Runtime.CompilerServices.INotifyCompletion
(daqui em diante, conhecida comoINotifyCompletion
para fins de brevidade)A
implements the interfaceSystem.Runtime.CompilerServices.INotifyCompletion
(hereafter known asINotifyCompletion
for brevity)A
tem uma propriedade de instância legível e acessívelIsCompleted
do tipobool
A
has an accessible, readable instance propertyIsCompleted
of typebool
A
tem um método de instância acessível semGetResult
parâmetros e nenhum parâmetro de tipoA
has an accessible instance methodGetResult
with no parameters and no type parameters
A finalidade do GetAwaiter
método é obter um *awaitr _ para a tarefa.The purpose of the GetAwaiter
method is to obtain an *awaiter _ for the task. O tipo A
é chamado _ aguardador tipo* para a expressão Await.The type A
is called the _ awaiter type* for the await expression.
A finalidade da IsCompleted
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 há necessidade de suspender a avaliação.If so, there is no need to suspend evaluation.
A finalidade do INotifyCompletion.OnCompleted
método é inscrever uma "continuação" para a tarefa; ou seja, um delegado (do tipo System.Action
) que será invocado assim que 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 do 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 uma conclusão bem-sucedida, possivelmente com um valor de resultado, ou pode ser uma exceção que é gerada 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.
Classificação de expressões AwaitClassification of await expressions
A expressão await t
é classificada da mesma maneira 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
for void
, o await_expression será classificado como Nothing.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 void T
, o await_expression será 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
.
Avaliação de tempo de execução de expressões AwaitRuntime evaluation of await expressions
Em tempo de execução, a expressão await t
é avaliada da seguinte maneira:At runtime, the expression await t
is evaluated as follows:
- Um esperador
a
é obtido avaliando a expressão(t).GetAwaiter()
.An awaitera
is obtained by evaluating the expression(t).GetAwaiter()
. - R
bool
b
é obtido avaliando a expressão(a).IsCompleted
.Abool
b
is obtained by evaluating the expression(a).IsCompleted
. - Se
b
forfalse
, a avaliação dependerá sea
o implementará a interfaceSystem.Runtime.CompilerServices.ICriticalNotifyCompletion
(daqui em diante, conhecida comoICriticalNotifyCompletion
para fins de brevidade).Ifb
isfalse
then evaluation depends on whethera
implements the interfaceSystem.Runtime.CompilerServices.ICriticalNotifyCompletion
(hereafter known asICriticalNotifyCompletion
for brevity). Essa verificação é feita no momento da Associação; ou seja, em tempoa
de execução, se tiver o tipo de tempo de compilaçãodynamic
e, em caso contrário, o tempo de compilação.This check is done at binding time; i.e. at runtime ifa
has the compile time typedynamic
, and at compile time otherwise. Permitirr
denotar o delegado de continuação (funções assíncronas):Letr
denote the resumption delegate (Async functions):- Se não
a
implementarICriticalNotifyCompletion
, a expressão(a as (INotifyCompletion)).OnCompleted(r)
será avaliada.Ifa
does not implementICriticalNotifyCompletion
, then the expression(a as (INotifyCompletion)).OnCompleted(r)
is evaluated. - Se
a
implementaICriticalNotifyCompletion
, a expressão(a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r)
é avaliada.Ifa
does implementICriticalNotifyCompletion
, then the expression(a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r)
is evaluated. - A avaliação é suspensa e o controle é retornado para o chamador atual da função Async.Evaluation is then suspended, and control is returned to the current caller of the async function.
- Se não
- Imediatamente após (se
b
foitrue
), ou após a invocação posterior do delegado de continuação (seb
foifalse
), a expressão(a).GetResult()
é avaliada.Either immediately after (ifb
wastrue
), or upon later invocation of the resumption delegate (ifb
wasfalse
), the expression(a).GetResult()
is evaluated. Se ele retornar um valor, esse valor será o resultado da await_expression.If it returns a value, that value is the result of the await_expression. Caso contrário, o resultado será Nothing.Otherwise the result is nothing.
A implementação de um esperador dos métodos de interface INotifyCompletion.OnCompleted
e ICriticalNotifyCompletion.UnsafeOnCompleted
deve fazer com que o delegado r
seja 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 assíncrona delimitadora será indefinido.Otherwise, the behavior of the enclosing async function is undefined.
Operadores aritméticosArithmetic operators
Os *
operadores,, /
%
, +
e -
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 de um operador aritmético tiver o tipo de tempo de compilação dynamic
, a expressão será vinculada dinamicamente (associaçã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 abaixo ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que têm 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
, a resolução de sobrecarga de operador binário (resolução de sobrecarga deoperador binário) é aplicada para selecionar uma implementação de operador específica.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 de 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 computam o produto do x
e do 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 estiver fora do intervalo do tipo de resultado, umSystem.OverflowException
será lançado.In achecked
context, if the product is outside the range of the result type, aSystem.OverflowException
is thrown. Em umunchecked
contexto, os estouros não são relatados e quaisquer bits de ordem superior significativos fora do intervalo do tipo de resultado são descartados.In anunchecked
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 de 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 finitos diferentes de zero, zeros, infinitos e NaNs.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Na tabela,
x
ey
são valores positivos finitos.In the table,x
andy
are positive finite values.z
é o resultado dex * y
.z
is the result ofx * y
. Se o resultado é grande demais para o tipo de destino,z
é infinito.If the result is too large for the destination type,z
is infinity. Se o resultado é pequeno demais 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 for muito grande para representar no
decimal
formato, umSystem.OverflowException
será lançado.If the resulting value is too large to represent in thedecimal
format, aSystem.OverflowException
is thrown. Se o valor do resultado for muito pequeno para representar nodecimal
formato, o resultado será zero.If the result value is too small to represent in thedecimal
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.A 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 typeSystem.Decimal
.
Operador de divisãoDivision operator
Para uma operação do formulário x / y
, a resolução de sobrecarga de operador binário (resolução de sobrecarga deoperador binário) é aplicada para selecionar uma implementação de operador específica.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 de 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. Todos os operadores computam o quociente de x
e y
.The operators all compute the quotient of x
and y
.
Divisão de inteiro: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 direito for zero, um
System.DivideByZeroException
será lançado.If the value of the right operand is zero, aSystem.DivideByZeroException
is thrown.A divisão arredonda o resultado em direção a zero.The division rounds the result towards zero. Portanto, o valor absoluto do resultado é o maior inteiro possível que é menor ou igual ao valor absoluto do quociente dos 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 negativos quando os dois operandos têm sinais opostos.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 o menor valor representável
int
oulong
o operando direito for-1
, ocorrerá um estouro.If the left operand is the smallest representableint
orlong
value and the right operand is-1
, an overflow occurs. Em umchecked
contexto, isso faz com que umaSystem.ArithmeticException
(ou uma subclasse dele) seja gerada.In achecked
context, this causes aSystem.ArithmeticException
(or a subclass thereof) to be thrown. Em umunchecked
contexto, ele é definido pela implementação para se umaSystem.ArithmeticException
(ou uma subclasse) for gerada ou se o estouro não for relatado com o valor resultante sendo o do operando esquerdo.In anunchecked
context, it is implementation-defined as to whether aSystem.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 de 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 finitos diferentes de zero, zeros, infinitos e NaNs.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Na tabela,
x
ey
são valores positivos finitos.In the table,x
andy
are positive finite values.z
é o resultado dex / y
.z
is the result ofx / y
. Se o resultado é grande demais para o tipo de destino,z
é infinito.If the result is too large for the destination type,z
is infinity. Se o resultado é pequeno demais 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 direito for zero, um
System.DivideByZeroException
será lançado.If the value of the right operand is zero, aSystem.DivideByZeroException
is thrown. Se o valor resultante for muito grande para representar nodecimal
formato, umSystem.OverflowException
será lançado.If the resulting value is too large to represent in thedecimal
format, aSystem.OverflowException
is thrown. Se o valor do resultado for muito pequeno para representar nodecimal
formato, o resultado será zero.If the result value is too small to represent in thedecimal
format, the result is zero. A escala do resultado é a menor escala que preservará um resultado igual ao valor decimal representável mais próximo para o resultado matemático verdadeiro.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.A 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 typeSystem.Decimal
.
Operador de restoRemainder operator
Para uma operação do formulário x % y
, a resolução de sobrecarga de operador binário (resolução de sobrecarga deoperador binário) é aplicada para selecionar uma implementação de operador específica.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 de 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 restantes predefinidos estão listados abaixo.The predefined remainder operators are listed below. Todos os operadores calculam o restante da divisão entre x
e y
.The operators all compute the remainder of the division between x
and y
.
Restante do 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 porx - (x / y) * y
.The result ofx % y
is the value produced byx - (x / y) * y
. Sey
for zero, umSystem.DivideByZeroException
será lançado.Ify
is zero, aSystem.DivideByZeroException
is thrown.Se o operando esquerdo for o menor
int
long
valor, e o operando direito for-1
, umSystem.OverflowException
será lançado.If the left operand is the smallestint
orlong
value and the right operand is-1
, aSystem.OverflowException
is thrown. Em nenhum caso, ox % y
gera uma exceção em quex / y
não geraria uma exceção.In no case doesx % y
throw an exception wherex / y
would not throw an exception.Restante do ponto flutuante: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 finitos diferentes de zero, zeros, infinitos e NaNs.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Na tabela,
x
ey
são valores positivos finitos.In the table,x
andy
are positive finite values.z
é o resultado dex % y
e é calculado comox - n * y
, em quen
é o maior inteiro possível que é menor ou igual ax / y
.z
is the result ofx % y
and is computed asx - n * y
, wheren
is the largest possible integer that is less than or equal tox / y
. Esse método de computação do restante é análogo ao usado para operandos inteiros, mas difere da definição do IEEE 754 (em quen
é o número inteiro mais próximo dex / y
).This method of computing the remainder is analogous to that used for integer operands, but differs from the IEEE 754 definition (in whichn
is the integer closest tox / 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 Restante decimal:Decimal remainder:
decimal operator %(decimal x, decimal y);
Se o valor do operando direito for zero, um
System.DivideByZeroException
será lançado.If the value of the right operand is zero, aSystem.DivideByZeroException
is thrown. A escala do resultado, antes de qualquer arredondamento, é maior das escalas dos dois operandos, e o sinal do resultado, se for diferente de zero, é igual ao dex
.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 ofx
.O restante decimal é equivalente a usar o operador restante do tipo
System.Decimal
.Decimal remainder is equivalent to using the remainder operator of typeSystem.Decimal
.
Operador de adiçãoAddition operator
Para uma operação do formulário x + y
, a resolução de sobrecarga de operador binário (resolução de sobrecarga deoperador binário) é aplicada para selecionar uma implementação de operador específica.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 de 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 predefinidos 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 computam 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 concatenam 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 estiver fora do intervalo do tipo de resultado, umSystem.OverflowException
será lançado.In achecked
context, if the sum is outside the range of the result type, aSystem.OverflowException
is thrown. Em umunchecked
contexto, os estouros não são relatados e quaisquer bits de ordem superior significativos fora do intervalo do tipo de resultado são descartados.In anunchecked
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 de 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 finitos diferentes de zero, zeros, infinitos e NaNs.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Na tabela,
x
ey
são valores finitos diferentes de zero ez
é o resultado dex + y
.In the table,x
andy
are nonzero finite values, andz
is the result ofx + y
. Sex
ey
tiverem a mesma magnitude, mas sinais opostos,z
será zero positivo.Ifx
andy
have the same magnitude but opposite signs,z
is positive zero. Sex + y
for muito grande para representar no tipo de destino,z
é um infinito com o mesmo sinal dex + y
.Ifx + y
is too large to represent in the destination type,z
is an infinity with the same sign asx + y
.ay +0+0 -0-0 +inf+inf -inf-inf NaNNaN xx zz xx xx +inf+inf -inf-inf NaNNaN +0+0 ay +0+0 +0+0 +inf+inf -inf-inf NaNNaN -0-0 ay +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 for muito grande para representar no
decimal
formato, umSystem.OverflowException
será lançado.If the resulting value is too large to represent in thedecimal
format, aSystem.OverflowException
is thrown. A escala do resultado, antes de qualquer arredondamento, é maior das escalas dos dois operandos.The scale of the result, before any rounding, is the larger of the scales of the two operands.A 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 typeSystem.Decimal
.Adição de enumeração.Enumeration addition. Cada tipo de enumeração fornece implicitamente os seguintes operadores predefinidos, em que
E
é o tipo de enumeração eU
é o tipo subjacente deE
:Every enumeration type implicitly provides the following predefined operators, whereE
is the enum type, andU
is the underlying type ofE
: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 operador binário
+
executam a concatenação de cadeia de caracteres.These overloads of the binary+
operator perform string concatenation. Se um operando da concatenação de cadeia de caracteres fornull
, uma cadeia de caracteres vazia será substituída.If an operand of string concatenation isnull
, an empty string is substituted. Caso contrário, qualquer argumento que não seja de cadeia de caracteres é convertido em sua representação de cadeia de caracteres invocando oToString
método virtual herdado do tipoobject
.Otherwise, any non-string argument is converted to its string representation by invoking the virtualToString
method inherited from typeobject
. SeToString
retornarnull
, uma cadeia de caracteres vazia será substituída.IfToString
returnsnull
, 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 nos caracteres do operando esquerdo seguidos dos caracteres do operando à direita. O operador de concatenação de cadeia de caracteres nunca retorna um
null
valor. UmSystem.OutOfMemoryException
pode ser gerado se não houver memória suficiente disponível para alocar a cadeia de caracteres resultante.ASystem.OutOfMemoryException
may be thrown if there is not enough memory available to allocate the resulting string.Combinação de delegado.Delegate combination. Cada tipo delegado implicitamente fornece o seguinte operador predefinido, em que
D
é o tipo delegado:Every delegate type implicitly provides the following predefined operator, whereD
is the delegate type:D operator +(D x, D y);
O
+
operador binário executa a combinação de delegado quando ambos os operandos são de algum tipo delegadoD
.The binary+
operator performs delegate combination when both operands are of some delegate typeD
. (Se os operandos tiverem tipos delegados diferentes, ocorrerá um erro de tempo de associação.) Se o primeiro operando fornull
, o resultado da operação será o valor do segundo operando (mesmo que também estejanull
).(If the operands have different delegate types, a binding-time error occurs.) If the first operand isnull
, the result of the operation is the value of the second operand (even if that is alsonull
). Caso contrário, se o segundo operando fornull
, o resultado da operação será o valor do primeiro operando.Otherwise, if the second operand isnull
, 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 de delegado que, quando invocada, 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 delegado, consulte operador de subtração e invocação de delegado.For examples of delegate combination, see Subtraction operator and Delegate invocation. ComoSystem.Delegate
não é um tipo delegado,operator
+
não está definido para ele.SinceSystem.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
, a resolução de sobrecarga de operador binário (resolução de sobrecarga deoperador binário) é aplicada para selecionar uma implementação de operador específica.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 de 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 predefinidos estão listados abaixo.The predefined subtraction operators are listed below. Todos os operadores são subtraídos y
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 estiver fora do intervalo do tipo de resultado, umSystem.OverflowException
será lançado.In achecked
context, if the difference is outside the range of the result type, aSystem.OverflowException
is thrown. Em umunchecked
contexto, os estouros não são relatados e quaisquer bits de ordem superior significativos fora do intervalo do tipo de resultado são descartados.In anunchecked
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 de 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 finitos diferentes 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
ey
são valores finitos diferentes de zero ez
é o resultado dex - y
.In the table,x
andy
are nonzero finite values, andz
is the result ofx - y
. Sex
ey
forem iguais,z
será zero positivo.Ifx
andy
are equal,z
is positive zero. Sex - y
for muito grande para representar no tipo de destino,z
é um infinito com o mesmo sinal dex - y
.Ifx - y
is too large to represent in the destination type,z
is an infinity with the same sign asx - y
.ay +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 for muito grande para representar no
decimal
formato, umSystem.OverflowException
será lançado.If the resulting value is too large to represent in thedecimal
format, aSystem.OverflowException
is thrown. A escala do resultado, antes de qualquer arredondamento, é maior das escalas dos dois operandos.The scale of the result, before any rounding, is the larger of the scales of the two operands.A subtração decimal é equivalente a usar o operador de subtração do tipo
System.Decimal
.Decimal subtraction is equivalent to using the subtraction operator of typeSystem.Decimal
.Subtração de enumeração.Enumeration subtraction. Cada tipo de enumeração fornece implicitamente o seguinte operador predefinido, em que
E
é o tipo de enumeração eU
é o tipo subjacente deE
:Every enumeration type implicitly provides the following predefined operator, whereE
is the enum type, andU
is the underlying type ofE
: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 computa a diferença entre os valores ordinais dex
e ey
o tipo do resultado é o tipo subjacente da enumeração.In other words, the operator computes the difference between the ordinal values ofx
andy
, 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, produzindo 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 delegado implicitamente fornece o seguinte operador predefinido, em que
D
é o tipo delegado:Every delegate type implicitly provides the following predefined operator, whereD
is the delegate type:D operator -(D x, D y);
O
-
operador binário executa a remoção de delegado quando ambos os operandos são de algum tipo delegadoD
.The binary-
operator performs delegate removal when both operands are of some delegate typeD
. Se os operandos tiverem tipos delegados diferentes, ocorrerá um erro de tempo de associação.If the operands have different delegate types, a binding-time error occurs. Se o primeiro operando fornull
, o resultado da operação seránull
.If the first operand isnull
, the result of the operation isnull
. Caso contrário, se o segundo operando fornull
, o resultado da operação será o valor do primeiro operando.Otherwise, if the second operand isnull
, then the result of the operation is the value of the first operand. Caso contrário, os dois operandos representam listas de invocação (declarações de delegado) que têm uma ou mais entradas e o resultado é uma nova lista de invocação que consiste na lista do primeiro operando com as entradas do segundo operando removidas, desde que a lista do segundo operando seja 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 a igualdade da sublista, as entradas correspondentes são comparadas com o operador de igualdade de delegado (operadores de igualdade de delegado).) Caso contrário, o resultado será o valor do operando esquerdo.(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 de 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 de entradas contíguas na lista do primeiro operando, a sublista correspondente à direita de entradas contíguas será 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 a remoção resultar em uma lista vazia, o resultado seránull
.If removal results in an empty list, the result isnull
. 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
Os <<
>>
operadores e 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 tiver o tipo de tempo de compilação dynamic
, a expressão será vinculada dinamicamente (associaçã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 abaixo ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que têm 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 da forma x << count
ou x >> count
, a resolução de sobrecarga de operador binário (resolução de sobrecarga de operador binário) é aplicada para selecionar uma implementação de operador específica.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 de 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 sempre deve ser 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 de alternância predefinidos estão listados abaixo.The predefined shift operators are listed below.
Deslocar para a esquerda: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
<<
operador mudax
para a esquerda por um número de bits calculados, conforme descrito abaixo.The<<
operator shiftsx
left by a number of bits computed as described below.Os bits de ordem superior fora do intervalo do tipo de resultado de
x
são descartados, os bits restantes são deslocados para a esquerda e as posições de bit em branco de ordem inferior são definidas como zero.The high-order bits outside the range of the result type ofx
are discarded, the remaining bits are shifted left, and the low-order empty bit positions are set to zero.Deslocar para a direita: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
>>
operador mudax
para a direita por um número de bits calculados, conforme descrito abaixo.The>>
operator shiftsx
right by a number of bits computed as described below.Quando
x
é do tipoint
oulong
, os bits de ordem inferior dex
são descartados, os bits restantes são deslocados para a direita e as posições de bits vazias de ordem superior são definidas como zero sex
não forem negativas e definidas como um sex
forem negativas.Whenx
is of typeint
orlong
, the low-order bits ofx
are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero ifx
is non-negative and set to one ifx
is negative.Quando
x
é do tipouint
ouulong
, os bits de ordem inferior dex
são descartados, os bits restantes são deslocados para a direita e as posições de bits vazias de ordem superior são definidas como zero.Whenx
is of typeuint
orulong
, the low-order bits ofx
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 serem deslocados é calculado da seguinte maneira:For the predefined operators, the number of bits to shift is computed as follows:
- Quando o tipo de
x
éint
ouuint
, a contagem de deslocamento é fornecida pelos cinco bits de ordem inferior decount
.When the type ofx
isint
oruint
, the shift count is given by the low-order five bits ofcount
. Em outras palavras, a contagem de deslocamento é calculada a partir decount & 0x1F
.In other words, the shift count is computed fromcount & 0x1F
. - Quando o tipo de
x
élong
ouulong
, a contagem de deslocamento é fornecida pelos seis bits de ordem inferior decount
.When the type ofx
islong
orulong
, the shift count is given by the low-order six bits ofcount
. Em outras palavras, a contagem de deslocamento é calculada a partir decount & 0x3F
.In other words, the shift count is computed fromcount & 0x3F
.
Se a contagem de deslocamento resultante for zero, os operadores de alternância simplesmente retornarão o valor de x
.If the resulting shift count is zero, the shift operators simply return the value of x
.
As operações de Shift nunca causam estouros e produzem os mesmos resultados checked
e unchecked
contextos.Shift operations never cause overflows and produce the same results in checked
and unchecked
contexts.
Quando o operando esquerdo do >>
operador for de um tipo integral assinado, o operador executará um deslocamento aritmético à direita no qual o valor do bit mais significativo (o bit de sinal) do operando será propagado para as posições de bit vazio de ordem superior.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 esquerdo do >>
operador é de um tipo integral não assinado, o operador executa um direito de deslocamento lógico onde as posições de bits vazias de ordem superior 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 da inferida do tipo de operando, as conversões explícitas podem ser usadas.To perform the opposite operation of that inferred from the operand type, explicit casts can be used. Por exemplo, se x
for uma variável do tipo int
, a operação unchecked((int)((uint)x >> y))
executará um deslocamento lógico à direita de x
.For example, if x
is a variable of type int
, the operation unchecked((int)((uint)x >> y))
performs a logical shift right of x
.
Operadores de teste de tipo e relacionalRelational and type-testing operators
Os ==
operadores,,,,, !=
<
>
<=
>=
is
e as
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 no operador is e o as
operador é descrito no operador as.The is
operator is described in The is operator and the as
operator is described in The as operator.
Os ==
operadores,, !=
<
, >
<=
e >=
são operadores de comparação.The ==
, !=
, <
, >
, <=
and >=
operators are comparison operators.
Se um operando de um operador de comparação tiver o tipo de tempo de compilação dynamic
, a expressão será vinculada dinamicamente (associaçã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 abaixo ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que têm 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
, em que op é um operador de comparação, a resolução de sobrecarga (resolução de sobrecarga de operador binário) é aplicada para selecionar uma implementação de operador específica.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 de 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 predefinidos 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 | ResultadoResult |
---|---|
x == y |
true Se x for igual a y , false caso contrário,true if x is equal to y , false otherwise |
x != y |
true Se x não for igual a y , false caso contrário,true if x is not equal to y , false otherwise |
x < y |
true se x for menor que y , caso contrário, false true if x is less than y , false otherwise |
x > y |
true se x for maior que y , caso contrário, false true if x is greater than y , false otherwise |
x <= y |
true se x for menor ou igual a y , caso contrário, false true if x is less than or equal to y , false otherwise |
x >= y |
true se x for maior ou igual a y , caso contrário, false true if x is greater than or equal to y , false otherwise |
Operadores de comparação de inteirosInteger comparison operators
Os operadores de comparação de inteiros 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 dois operandos 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 os quais o resultado étrue
.If either operand is NaN, the result isfalse
for all operators except!=
, for which the result istrue
. Para quaisquer dois operandos,x != y
o 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, os<
operadores,,>
<=
e>=
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 um dosx
ey
for NaN, entãox < y
éfalse
, mas!(x >= y)
étrue
.For example, if either ofx
andy
is NaN, thenx < y
isfalse
, but!(x >= y)
istrue
.Quando nenhum operando é NaN, os operadores comparam os valores dos dois operandos de ponto flutuante em relação à 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
onde
min
emax
são os valores finitos menores e maiores positivos que podem ser representados no formato de ponto flutuante fornecido.wheremin
andmax
are the smallest and largest positive finite values that can be represented in the given floating-point format. Os efeitos notáveis dessa ordenação são:Notable effects of this ordering are:- Zeros negativos e positivos são considerados iguais.Negative and positive zeros are considered equal.
- Um infinito negativo é considerado menor 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 infinito positivo é considerado maior que todos os outros valores, mas é igual a 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 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 operando 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 relacional ou de igualdade correspondente do tipo System.Decimal
.Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal
.
Operadores de igualdade boolianosBoolean equality operators
Os operadores de igualdade boolianos predefinidos são:The predefined boolean equality operators are:
bool operator ==(bool x, bool y);
bool operator !=(bool x, bool y);
O resultado de ==
é true
se x
e y
são true
ou se ambos forem x
y
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 !=
é false
se x
e y
são true
ou se ambos forem x
y
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 produzirá 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 fornece implicitamente 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 avaliar ((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 apenas 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 predefinido 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 da comparação das duas referências para igualdade ou não igualdade.The operators return the result of comparing the two references for equality or non-equality.
Como os operadores de igualdade do tipo de referência predefinido aceitam operandos do tipo object
, eles se aplicam a todos os tipos que não declaram operator ==
operator !=
os membros e aplicáveis.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 operador de igualdade definido pelo usuário aplicável efetivamente oculta os operadores de igualdade do tipo de referência predefinido.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 dos seguintes:The predefined reference type equality operators require one of the following:
- Ambos os operandos são um valor de um tipo conhecido como um reference_type ou o literal
null
.Both operands are a value of a type known to be a reference_type or the literalnull
. Além disso, uma conversão de referência explícita (conversões de referência explícitas) existe no tipo de um dos operandos para o tipo do 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 é um valor do tipo
T
, em queT
é um type_parameter e o outro operando é o literalnull
.One operand is a value of typeT
whereT
is a type_parameter and the other operand is the literalnull
. Além disso,T
não tem a restrição de tipo de valor.FurthermoreT
does not have the value type constraint.
A menos que uma dessas condições seja verdadeira, ocorre um erro de tempo de associação.Unless one of these conditions are true, a binding-time error occurs. As principais implicações dessas regras são:Notable implications of these rules are:
- É um erro de tempo de ligação para usar os operadores de igualdade do tipo de referência predefinido para comparar duas referências que são conhecidas para serem diferentes no 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 dos operandos forem dois tipos de classe
A
eB
, e se nem foremA
B
derivados do outro, seria impossível para os dois operandos referenciarem o mesmo objeto.For example, if the binding-time types of the operands are two class typesA
andB
, and if neitherA
norB
derives from the other, then it would be impossible for the two operands to reference the same object. Assim, 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 predefinido não permitem que os operandos de tipo de valor sejam comparados.The predefined reference type equality operators do not permit value type operands to be compared. Portanto, a menos que um tipo de struct declare seus próprios operadores de igualdade, não é possível comparar valores desse tipo 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 predefinido nunca causam a ocorrência de operações Boxing para seus operandos.The predefined reference type equality operators never cause boxing operations to occur for their operands. Seria sem sentido executar essas operações boxing, já que as referências às instâncias emolduradas recentemente alocadas seriam necessariamente diferentes 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
for comparado anull
, e o tipo de tempo de execução deT
for um tipo de valor, o resultado da comparação seráfalse
.If an operand of a type parameter typeT
is compared tonull
, and the run-time type ofT
is a value type, the result of the comparison isfalse
.
O exemplo a seguir verifica se um argumento de um tipo de parâmetro de tipo irrestrito é 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();
...
}
}
A x == null
construção é permitida mesmo que T
possa representar um tipo de valor, e o resultado é simplesmente definido como 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 aplicável operator ==
ou operator !=
existir, as regras de resolução de sobrecarga de operador (resolução de sobrecarga de operador binário) selecionarão esse operador em vez do operador de igualdade do tipo de referência predefinido.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 predefinido, 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
As s
t
variáveis e referem-se a duas instâncias distintas string
contendo 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 predefinido (operadores de igualdade de cadeia de caracteres) é selecionado quando ambos os operandos são 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
. As comparações restantes são todas saídas False
porque o tipo de referência predefinido operador de igualdade é selecionado quando um ou ambos os operandos são 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);
}
}
saídas False
porque as conversões criam referências a duas instâncias separadas de valores de caixa int
.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 predefinidos 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 é verdadeira:Two string
values are considered equal when one of the following is true:
- Ambos os valores são
null
.Both values arenull
. - Ambos os valores são referências não nulas a instâncias de cadeia de caracteres que têm comprimentos idênticos e caracteres idênticos em cada posição de 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ênciasThe string equality operators compare string values rather than string references. Quando duas instâncias de cadeias de caracteres separadas contêm exatamente a mesma sequência de caracteres, os valores das cadeias 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 de tipo de referência podem ser usados para comparar referências de cadeia de caracteres em vez de valores de cadeia de caracteresAs described in Reference type equality operators, the reference type equality operators can be used to compare string references instead of string values.
Delegar operadores de igualdadeDelegate equality operators
Cada tipo de delegado fornece implicitamente 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);
Duas instâncias de delegado são consideradas iguais da seguinte maneira:Two delegate instances are considered equal as follows:
- Se uma das instâncias de delegado for
null
, elas serão iguais se e somente se ambas estiveremnull
.If either of the delegate instances isnull
, they are equal if and only if both arenull
. - Se os delegados tiverem um tipo de tempo de execução diferente, nunca serão iguais.If the delegates have different run-time type they are never equal.
- Se ambas as instâncias de delegado tiverem uma lista de invocação (declarações de delegado), essas instâncias serão iguais se e somente se suas listas de invocação tiverem o mesmo comprimento, e cada entrada na lista de invocação de uma for igual (conforme definido abaixo) à entrada correspondente, na 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 regras a seguir regem a igualdade de entradas da lista de invocação:The following rules govern the equality of invocation list entries:
- Se duas entradas da lista de invocação fizerem referência ao mesmo método estático, as entradas serão iguais.If two invocation list entries both refer to the same static method then the entries are equal.
- Se duas entradas da lista de invocação fizerem referência ao mesmo método não-estático no mesmo objeto de destino (conforme definido pelos operadores de igualdade de referência), as entradas serã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.
- As entradas da lista de invocação produzidas da avaliação de anonymous_method_expression s ou lambda_expressions semanticamente idênticas com o mesmo conjunto (possivelmente vazio) de instâncias de variáveis externas capturadas são permitidas (mas não obrigatórias) para serem iguais.Invocation list entries produced from evaluation of semantically identical anonymous_method_expression s or lambda_expression s with the same (possibly empty) set of captured outer variable instances are permitted (but not required) to be equal.
Operadores de igualdade e nuloEquality operators and null
Os ==
!=
operadores e permitem que um operando seja um valor de um tipo anulável e o outro para ser o null
literal, mesmo que nenhum operador predefinido ou definido pelo usuário (em forma não elevada ou levantada) exista 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 um dos formuláriosFor an operation of one of the forms
x == null
null == x
x != null
null != x
em que x
é uma expressão de um tipo anulável, se a resolução de sobrecarga de operador (resolução de sobrecarga de operador binário) falhar ao localizar um operador aplicável, o resultado será computado a partir da 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 dois primeiros formulários são convertidos em !x.HasValue
e os últimos dois formulários são traduzidos para o x.HasValue
.Specifically, the first two forms are translated into !x.HasValue
, and last two forms are translated into x.HasValue
.
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
, em que E
é uma expressão e T
é um tipo, é um valor booliano que indica se é E
possível converter com êxito T
o tipo por uma conversão de referência, uma conversão boxing 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 da seguinte maneira, após os argumentos de tipo terem sido substituídos por todos os parâmetros de tipo:The operation is evaluated as follows, after type arguments have been substituted for all type parameters:
- Se
E
for uma função anônima, ocorrerá um erro de tempo de compilaçãoIfE
is an anonymous function, a compile-time error occurs - Se
E
for um grupo de métodos ou onull
literal, de se o tipo deE
for um tipo de referência ou um tipo anulável e o valor deE
for NULL, o resultado será false.IfE
is a method group or thenull
literal, of if the type ofE
is a reference type or a nullable type and the value ofE
is null, the result is false. - Caso contrário, permita
D
representar o tipo dinâmico de daE
seguinte maneira:Otherwise, letD
represent the dynamic type ofE
as follows:- Se o tipo de
E
for um tipo de referência,D
será o tipo de tempo de execução da referência de instância porE
.If the type ofE
is a reference type,D
is the run-time type of the instance reference byE
. - Se o tipo de
E
for um tipo anulável,D
será o tipo subjacente desse tipo anulável.If the type ofE
is a nullable type,D
is the underlying type of that nullable type. - Se o tipo de
E
for um tipo de valor não anulável,D
será o tipo deE
.If the type ofE
is a non-nullable value type,D
is the type ofE
.
- Se o tipo de
- O resultado da operação depende de
D
e daT
seguinte maneira:The result of the operation depends onD
andT
as follows:- Se
T
for um tipo de referência, o resultado será true seD
e forT
o mesmo tipo, seD
for um tipo de referência e uma conversão de referência implícita deD
paraT
Exists, ou seD
for um tipo de valor e uma conversão de Boxing deD
paraT
Exists.IfT
is a reference type, the result is true ifD
andT
are the same type, ifD
is a reference type and an implicit reference conversion fromD
toT
exists, or ifD
is a value type and a boxing conversion fromD
toT
exists. - Se
T
for um tipo anulável, o resultado será true seD
for o tipo subjacente deT
.IfT
is a nullable type, the result is true ifD
is the underlying type ofT
. - Se
T
for um tipo de valor não anulável, o resultado será true seD
eT
for do mesmo tipo.IfT
is a non-nullable value type, the result is true ifD
andT
are the same type. - Caso contrário, o resultado será false.Otherwise, the result is false.
- Se
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.
Operador asThe as operator
O as
operador é usado para converter explicitamente um valor em um determinado tipo de referência ou tipo anulável.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 será 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 como 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 um dos seguintes deve ser verdadeiro ou um erro de tempo de compilação ocorre:Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:
- Uma identidade (conversão de identidade), permite valor nulo implícito (conversões anuláveis implícitas), referência implícita (conversões de referência implícita), conversão de Boxing (conversões de Boxing), nulo explícito (conversões anuláveis explícitas), referência explícita (conversões de referência explícita) ou unboxing (conversões unboxing) existe de
E
paraT
.An identity (Identity conversion), implicit nullable (Implicit nullable conversions), implicit reference (Implicit reference conversions), boxing (Boxing conversions), explicit nullable (Explicit nullable conversions), explicit reference (Explicit reference conversions), or unboxing (Unboxing conversions) conversion exists fromE
toT
. - O tipo de
E
ouT
é um tipo aberto.The type ofE
orT
is an open type. E
é onull
literal.E
is thenull
literal.
Se o tipo de tempo de compilação de E
não for dynamic
, a operação E as T
produzirá 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 ideal para otimizar E as T
para executar no máximo uma verificação de tipo dinâmico, em oposição às duas verificações de tipo dinâmico, IMPLÍCITAS 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 de E
for dynamic
, ao contrário do operador cast, o as
operador não será 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, devem ser executadas 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 T
de tipo de G
é conhecido como 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 U
de tipo de H
não é no entanto; portanto, o uso do as
operador in não H
é 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
Os &
^
operadores, e |
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 tiver o tipo de tempo de compilação dynamic
, a expressão será vinculada dinamicamente (associaçã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 abaixo ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que têm 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
, em que op
é um dos operadores lógicos, a resolução de sobrecarga (resolução de sobrecarga do operador binário) é aplicada para selecionar uma implementação de operador específica.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 de 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 inteirosInteger 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 computa o bit lógico AND
dos dois operandos, |
e o operador computa a lógica de bits de bit e lógico dos dois OR
operandos, e o ^
operador computa o exclusivo lógico bit-a OR
de 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 são possíveis estouros dessas operações.No overflows are possible from these operations.
Operadores lógicos de enumeraçãoEnumeration logical operators
Cada tipo de enumeração E
fornece implicitamente os seguintes operadores lógicos predefinidos: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 avaliar (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 do 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
é true
se 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
é true
If x
true
e y
is 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 são do tipo bool
, o ^
operador computa 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 anuláveisNullable boolean logical operators
O tipo booliano Anulável bool?
pode representar três valores, true
, false
e null
, e é conceitualmente semelhante ao tipo de três valores usado para expressões boolianas no 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 &
operadores e |
para bool?
operandos sejam 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
Os operadores &&
e ||
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 de "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
;
Os &&
||
operadores e são versões condicionais dos &
|
operadores e:The &&
and ||
operators are conditional versions of the &
and |
operators:
- A operação
x && y
corresponde à operaçãox & y
, exceto quey
só será avaliada sex
não forfalse
.The operationx && y
corresponds to the operationx & y
, except thaty
is evaluated only ifx
is notfalse
. - A operação
x || y
corresponde à operaçãox | y
, exceto quey
só será avaliada sex
não fortrue
.The operationx || y
corresponds to the operationx | y
, except thaty
is evaluated only ifx
is nottrue
.
Se um operando de um operador lógico condicional tiver o tipo de tempo de compilação dynamic
, a expressão será vinculada dinamicamente (associaçã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 abaixo ocorrerá em tempo de execução usando o tipo de tempo de execução desses operandos que têm 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 pela aplicação da resolução de sobrecarga (resolução de sobrecarga do operador binário) como se a operação fosse gravada 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
. E, em seguida,Then,
- Se a resolução de sobrecarga não encontrar um único operador melhor, ou se a resolução de sobrecarga selecionar um dos operadores lógicos inteiros predefinidos, ocorrerá um erro de tempo de associação.If overload resolution fails to find a single best operator, or if overload resolution selects one of the predefined integer logical operators, a binding-time error occurs.
- Caso contrário, se o operador selecionado for um dos operadores lógicos boolianos predefinidos (operadores lógicos boolianos) ou operadores lógicos boolianos anuláveis (operadores lógicos boolianos anuláveis), a operação será processada conforme descrito em operadores lógicos condicionais boolianos.Otherwise, if the selected operator is one of the predefined boolean logical operators (Boolean logical operators) or nullable boolean logical operators (Nullable boolean logical operators), the operation is processed as described in Boolean conditional logical operators.
- Caso contrário, o operador selecionado é um operador definido pelo usuário e a operação é processada conforme descrito em operadores lógicos condicionais definidos pelo usuário.Otherwise, the selected operator is a user-defined operator, and the operation is processed as described in User-defined conditional logical operators.
Não é possível sobrecarregar diretamente os operadores lógicos condicionais.It is not possible to directly overload the conditional logical operators. No entanto, como os operadores lógicos condicionais são avaliados em termos de operadores lógicos regulares, as sobrecargas dos operadores lógicos regulares são, com certas restrições, também 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 mais detalhadamente em operadores lógicos condicionais definidos pelo usuário.This is described further in User-defined conditional logical operators.
Operadores lógicos condicionais boolianosBoolean conditional logical operators
Quando os operandos de &&
ou ||
são do tipo bool
, ou quando os operandos são de tipos que não definem uma aplicável operator &
ou operator |
, mas definem conversões implícitas para bool
o, a operação é processada 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 comox ? y : false
.The operationx && y
is evaluated asx ? y : false
. Em outras palavras,x
é avaliado primeiro e convertido em tipobool
.In other words,x
is first evaluated and converted to typebool
. Em seguida, sex
fortrue
,y
será avaliado e convertido em tipobool
, e isso se tornará o resultado da operação.Then, ifx
istrue
,y
is evaluated and converted to typebool
, and this becomes the result of the operation. Caso contrário, o resultado da operação seráfalse
.Otherwise, the result of the operation isfalse
. - A operação
x || y
é avaliada comox ? true : y
.The operationx || y
is evaluated asx ? true : y
. Em outras palavras,x
é avaliado primeiro e convertido em tipobool
.In other words,x
is first evaluated and converted to typebool
. Em seguida, sex
fortrue
, o resultado da operação serátrue
.Then, ifx
istrue
, the result of the operation istrue
. Caso contrário,y
é avaliado e convertido parabool
o tipo, e isso se torna o resultado da operação.Otherwise,y
is evaluated and converted to typebool
, 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 definido pelo usuário aplicável operator &
ou operator |
, ambos devem ser verdadeiros, em que 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 beT
. Em outras palavras, o operador deve calcular o lógicoAND
ou lógicoOR
de dois operandos do tipoT
e deve retornar um resultado do tipoT
.In other words, the operator must compute the logicalAND
or the logicalOR
of two operands of typeT
, and must return a result of typeT
. T
deve conter declarações deoperator true
eoperator false
.T
must contain declarations ofoperator true
andoperator false
.
Um erro de tempo de associação ocorre se um desses requisitos não for atendido.A binding-time error occurs if either of these requirements is not satisfied. Caso contrário, &&
a ||
operação ou é avaliada pela combinação do 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
é avaliada comoT.false(x) ? x : T.&(x, y)
, em queT.false(x)
é uma invocação dooperator false
declarado emT
eT.&(x, y)
é uma invocação do selecionadooperator &
.The operationx && y
is evaluated asT.false(x) ? x : T.&(x, y)
, whereT.false(x)
is an invocation of theoperator false
declared inT
, andT.&(x, y)
is an invocation of the selectedoperator &
. Em outras palavras, ox
é avaliado pela primeira vez eoperator false
é invocado no resultado para determinar sex
é definitivamente falso.In other words,x
is first evaluated andoperator false
is invoked on the result to determine ifx
is definitely false. Em seguida, sex
for definitivamente false, o resultado da operação será o valor calculado anteriormente parax
.Then, ifx
is definitely false, the result of the operation is the value previously computed forx
. Caso contrário,y
é avaliado, e o selecionadooperator &
é invocado no valor calculado anteriormente parax
e o valor calculado paray
para produzir o resultado da operação.Otherwise,y
is evaluated, and the selectedoperator &
is invoked on the value previously computed forx
and the value computed fory
to produce the result of the operation. - A operação
x || y
é avaliada comoT.true(x) ? x : T.|(x, y)
, em queT.true(x)
é uma invocação dooperator true
declarado emT
eT.|(x,y)
é uma invocação do selecionadooperator|
.The operationx || y
is evaluated asT.true(x) ? x : T.|(x, y)
, whereT.true(x)
is an invocation of theoperator true
declared inT
, andT.|(x,y)
is an invocation of the selectedoperator|
. Em outras palavras, ox
é avaliado pela primeira vez eoperator true
é invocado no resultado para determinar sex
é definitivamente verdadeiro.In other words,x
is first evaluated andoperator true
is invoked on the result to determine ifx
is definitely true. Em seguida, sex
for definitivamente verdadeiro, o resultado da operação será o valor calculado anteriormente parax
.Then, ifx
is definitely true, the result of the operation is the value previously computed forx
. Caso contrário,y
é avaliado, e o selecionadooperator |
é invocado no valor calculado anteriormente parax
e o valor calculado paray
para produzir o resultado da operação.Otherwise,y
is evaluated, and the selectedoperator |
is invoked on the value previously computed forx
and the value computed fory
to produce the result of the operation.
Em qualquer uma dessas operações, a expressão fornecida por x
é avaliada apenas uma vez e a expressão fornecida por y
não é avaliada ou avaliada exatamente 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 tipo booliano do banco de dados.For an example of a type that implements operator true
and operator false
, see Database boolean type.
O operador de coalescência nulaThe 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
que seja de um tipo anulável ou tipo de referência.A null coalescing expression of the form a ?? b
requires a
to be of a nullable type or reference type. Se a
for não nulo, o resultado será a ?? b
a
; caso contrário, o resultado será b
.If a
is non-null, the result of a ?? b
is a
; otherwise, the result is b
. A operação será avaliada b
somente se a
for NULL.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 a 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)
. Em termos gerais, uma expressão do formulário E1 ?? E2 ?? ... ?? En
retorna o primeiro dos operandos que não é nulo ou nulo se todos os operandos forem 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. Em ordem de preferência, o tipo de a ?? b
é A0
, A
, ou B
, em que A
é o tipo de a
(fornecido que a
tem um tipo), B
é o tipo de b
(fornecido que b
tem um tipo) e A0
é o tipo subjacente de A
If 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
o é processado da seguinte maneira:Specifically, a ?? b
is processed as follows:
- Se
A
existir e não for um tipo anulável ou um tipo de referência, ocorrerá um erro em tempo de compilação.IfA
exists and is not a nullable type or a reference type, a compile-time error occurs. - Se
b
for uma expressão dinâmica, o tipo de resultado serádynamic
.Ifb
is a dynamic expression, the result type isdynamic
. Em tempo de execução,a
é avaliado pela primeira vez.At run-time,a
is first evaluated. Sea
não for NULL,a
será convertido em dinâmico, e isso se tornará o resultado.Ifa
is not null,a
is converted to dynamic, and this becomes the result. Caso contrário,b
será avaliado, e isso se tornará o resultado.Otherwise,b
is evaluated, and this becomes the result. - Caso contrário, se
A
existir e for um tipo anulável e existir uma conversão implícita deb
paraA0
, o tipo de resultado seráA0
.Otherwise, ifA
exists and is a nullable type and an implicit conversion exists fromb
toA0
, the result type isA0
. Em tempo de execução,a
é avaliado pela primeira vez.At run-time,a
is first evaluated. Sea
não for NULL,a
será desencapsulado paraA0
o tipo e isso se tornará o resultado.Ifa
is not null,a
is unwrapped to typeA0
, and this becomes the result. Caso contrário,b
é avaliado e convertido paraA0
o tipo, e isso se torna o resultado.Otherwise,b
is evaluated and converted to typeA0
, and this becomes the result. - Caso contrário, se
A
existir e houver uma conversão implícita deb
paraA
, o tipo de resultado seráA
.Otherwise, ifA
exists and an implicit conversion exists fromb
toA
, the result type isA
. Em tempo de execução,a
é avaliado pela primeira vez.At run-time,a
is first evaluated. Sea
não for NULL,a
torna-se o resultado.Ifa
is not null,a
becomes the result. Caso contrário,b
é avaliado e convertido paraA
o tipo, e isso se torna o resultado.Otherwise,b
is evaluated and converted to typeA
, and this becomes the result. - Caso contrário, se houver
b
um tipoB
e uma conversão implícita dea
paraB
, o tipo de resultado seráB
.Otherwise, ifb
has a typeB
and an implicit conversion exists froma
toB
, the result type isB
. Em tempo de execução,a
é avaliado pela primeira vez.At run-time,a
is first evaluated. Sea
não for NULL,a
será desencapsulado paraA0
o tipo (seA
existir e for anulável) e convertido paraB
o tipo, e isso se tornará o resultado.Ifa
is not null,a
is unwrapped to typeA0
(ifA
exists and is nullable) and converted to typeB
, and this becomes the result. Caso contrário,b
será avaliado e se tornará o resultado.Otherwise,b
is evaluated and becomes the result. - Caso contrário,
a
eb
são incompatíveis e ocorre um erro de tempo de compilação.Otherwise,a
andb
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 ocorre à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
. Em seguida, se b
for true
, x
será avaliado e se tornará o resultado da operação.Then, if b
is true
, x
is evaluated and becomes the result of the operation. Caso contrário, y
será avaliado e se tornará o resultado da operação.Otherwise, y
is evaluated and becomes the result of the operation. Uma expressão condicional nunca avalia 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 a 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 possa ser convertida implicitamente 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 for atendido, ocorrerá um erro em tempo de compilação.If neither of these requirements is satisfied, a compile-time error occurs.
O segundo e o terceiro operandos, x
e y
, do ?:
operador Control 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
tiver tipoX
ey
tiver tipoY
,Ifx
has typeX
andy
has typeY
then- Se uma conversão implícita (conversões implícitas) existir de
X
paraY
, mas não deY
paraX
,Y
será o tipo da expressão condicional.If an implicit conversion (Implicit conversions) exists fromX
toY
, but not fromY
toX
, thenY
is the type of the conditional expression. - Se uma conversão implícita (conversões implícitas) existir de
Y
paraX
, mas não deX
paraY
,X
será o tipo da expressão condicional.If an implicit conversion (Implicit conversions) exists fromY
toX
, but not fromX
toY
, thenX
is the type of the conditional expression. - Caso contrário, nenhum tipo de expressão pode ser determinado e ocorre um erro em tempo de compilação.Otherwise, no expression type can be determined, and a compile-time error occurs.
- Se uma conversão implícita (conversões implícitas) existir de
- Se apenas um dos
x
ey
tiver um tipo, ex
ey
, forem conversíveis implicitamente para esse tipo, esse será o tipo da expressão condicional.If only one ofx
andy
has a type, and bothx
andy
, 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 em tempo de compilação.Otherwise, no expression type can be determined, and a compile-time error occurs.
O processamento em tempo de execução de uma expressão condicional do formulário b ? x : y
consiste nas seguintes etapas:The run-time processing of a conditional expression of the form b ? x : y
consists of the following steps:
- Primeiro,
b
é avaliado e obool
valor deb
é determinado:First,b
is evaluated, and thebool
value ofb
is determined:- Se uma conversão implícita do tipo de
b
abool
existir, essa conversão implícita será executada para produzir umbool
valor.If an implicit conversion from the type ofb
tobool
exists, then this implicit conversion is performed to produce abool
value. - Caso contrário, o
operator true
definido pelo tipo deb
é invocado para produzir umbool
valor.Otherwise, theoperator true
defined by the type ofb
is invoked to produce abool
value.
- Se uma conversão implícita do tipo de
- Se o
bool
valor produzido pela etapa acima fortrue
,x
será avaliado e convertido para o tipo da expressão condicional, e isso se tornará o resultado da expressão condicional.If thebool
value produced by the step above istrue
, thenx
is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression. - Caso contrário,
y
é avaliado e convertido para o tipo da 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 "embutida".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 próprio, mas é conversível em um delegate compatível ou tipo de árvore de expressão.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 delegado, a conversão será avaliada como um valor delegado que referencia o método que a função anônima define.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 será 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 motivos históricos, há dois tipos sintáticos de funções anônimas, ou seja, lambda_expression s e anonymous_method_expression s.For historical reasons there are two syntactic flavors of anonymous functions, namely lambda_expression s and anonymous_method_expression s. Para quase todas as finalidades, lambda_expression s são mais concisas e expressivas do que anonymous_method_expression s, que permanecem na linguagem para compatibilidade com versões anteriores.For almost all purposes, lambda_expression s are more concise and expressive than anonymous_method_expression s, which remain in the language for backwards compatibility.
lambda_expression
: anonymous_function_signature '=>' anonymous_function_body
;
anonymous_method_expression
: 'delegate' explicit_anonymous_function_signature? block
;
anonymous_function_signature
: explicit_anonymous_function_signature
| implicit_anonymous_function_signature
;
explicit_anonymous_function_signature
: '(' explicit_anonymous_function_parameter_list? ')'
;
explicit_anonymous_function_parameter_list
: explicit_anonymous_function_parameter (',' explicit_anonymous_function_parameter)*
;
explicit_anonymous_function_parameter
: anonymous_function_parameter_modifier? type identifier
;
anonymous_function_parameter_modifier
: 'ref'
| 'out'
;
implicit_anonymous_function_signature
: '(' implicit_anonymous_function_parameter_list? ')'
| implicit_anonymous_function_parameter
;
implicit_anonymous_function_parameter_list
: implicit_anonymous_function_parameter (',' implicit_anonymous_function_parameter)*
;
implicit_anonymous_function_parameter
: identifier
;
anonymous_function_body
: expression
| block
;
O =>
operador tem a mesma precedência de 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 funções assíncronas.An anonymous function with the async
modifier is an async function and follows the rules described in Async functions.
Os parâmetros de uma função anônima na forma de um lambda_expression podem ser digitados explícita ou implicitamente.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 explicitamente tipados, 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 Tipados implicitamente, os tipos dos parâmetros são inferidos do contexto no qual a função anônima ocorre — especificamente, quando a função anônima é convertida em um tipo de delegado compatível ou tipo de árvore de expressão, esse tipo fornece 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 único parâmetro tipado implicitamente, os parênteses 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
A lista de parâmetros de uma função anônima na forma de uma anonymous_method_expression é opcional.The parameter list of an anonymous function in the form of an anonymous_method_expression is optional. Se for fornecido, os parâmetros deverão ser tipados explicitamente.If given, the parameters must be explicitly typed. Caso contrário, a função anônima é conversível em um delegado com qualquer lista de parâmetros que não contenha out
parâmetros.If not, the anonymous function is convertible to a delegate with any parameter list not containing out
parameters.
Um corpo de bloco de uma função anônima pode ser acessado (pontos de extremidade e acessibilidade), a menos que a função anônima ocorra 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.
Veja a seguir alguns exemplos de funções anônimas: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_expression s e anonymous_method_expression s é o mesmo, exceto os seguintes pontos:The behavior of lambda_expression s and anonymous_method_expression s is the same except for the following points:
- anonymous_method_expression s permitem que a lista de parâmetros seja omitida inteiramente, produzindo convertibilidade para delegar tipos de qualquer lista de parâmetros de valor.anonymous_method_expression s permit the parameter list to be omitted entirely, yielding convertibility to delegate types of any list of value parameters.
- lambda_expression s permitem que os tipos de parâmetro sejam omitidos e inferidos, enquanto anonymous_method_expression s exigem que os tipos de parâmetros sejam declarados explicitamente.lambda_expression s permit parameter types to be omitted and inferred whereas anonymous_method_expression s require parameter types to be explicitly stated.
- O corpo de uma lambda_expression pode ser uma expressão ou um bloco de instrução, 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_expression s têm conversões para tipos de árvore de expressão compatíveis (tipos de árvore de expressão).Only lambda_expression s have conversions to compatible expression tree types (Expression tree types).
Assinaturas de funções anônimasAnonymous function signatures
O anonymous_function_signature opcional 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 da função anônima é 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 fornecido), o corpo do método anônimo 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). Portanto, é um erro de tempo de compilação para o nome de um parâmetro da função anônima corresponder ao nome de uma variável local, constante local ou parâmetro cujo escopo inclui a anonymous_method_expression ou lambda_expression.It is thus a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant or parameter whose scope includes the anonymous_method_expression or lambda_expression.
Se uma função anônima tiver um explicit_anonymous_function_signature, o conjunto de tipos de delegados compatíveis e tipos de árvore de expressão será restrito àqueles 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 grupos de métodos (conversões de grupos de métodos), não há suporte para a variância de contrato de 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 tiver um anonymous_function_signature, o conjunto de tipos de delegados compatíveis e tipos de árvore de expressão será restrito àqueles que não têm 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, um anonymous_function_signature pode ser compatível com um tipo delegado cuja lista de parâmetros contenha 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 a 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ções anônimasAnonymous function bodies
O corpo (expressão ou bloco) de uma função anônima está 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 incluir uma assinatura, os parâmetros especificados na assinatura estarã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 nenhuma assinatura, ela poderá ser convertida em um tipo de representante ou tipo de expressão com parâmetros (conversões de função anônimas), mas os parâmetros não poderão 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
osout
parâmetros ou especificados na assinatura (se houver) da função anônima delimitadora mais próxima, trata-se de um erro de tempo de compilação para o corpo acessar umref
out
parâmetro ou.Except forref
orout
parameters specified in the signature (if any) of the nearest enclosing anonymous function, it is a compile-time error for the body to access aref
orout
parameter. - Quando o tipo de
this
é um tipo de struct, é um erro de tempo de compilação para o corpo acessarthis
.When the type ofthis
is a struct type, it is a compile-time error for the body to accessthis
. Isso é verdadeiro se o acesso for explícito (como emthis.x
) ou implícito (como emx
ondex
é um membro de instância do struct).This is true whether the access is explicit (as inthis.x
) or implicit (as inx
wherex
is an instance member of the struct). Essa regra simplesmente proíbe esse acesso e não afeta se a pesquisa de membros resulta em um membro da estrutura.This rule simply prohibits such access and does not affect whether member lookup results in a member of the struct. - O corpo tem acesso às variáveis externas (variáveis externas) da função anônima.The body has access to the outer variables (Outer variables) of the anonymous function. O acesso de uma variável externa fará referência à instância da variável que está ativa no momento em que o lambda_expression ou anonymous_method_expression é avaliado (avaliação de expressões de função anônimas).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 uma instrução
goto
,break
instrução ou instruçãocontinue
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 agoto
statement,break
statement, orcontinue
statement whose target is outside the body or within the body of a contained anonymous function. - Uma
return
instrução no corpo retorna o controle de uma invocação da função anônima delimitadora mais próxima, não do membro da função delimitadora.Areturn
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 umareturn
instrução deve ser conversível implicitamente para o tipo de retorno do tipo delegado ou de árvore de expressão para o qual o lambda_expression ou anonymous_method_expression de delimitador mais próximo é convertido (conversões de função anônimas).An expression specified in areturn
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 é explicitamente não especificado se há qualquer maneira de executar o bloco de uma função anônima além da 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 sintetizando um ou mais métodos ou tipos nomeados.In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types. Os nomes de quaisquer elementos sintetizados devem ser de um formulário reservado para uso do 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
As funções anônimas em uma lista de argumentos participam da inferência de tipos e da resolução de sobrecarga.Anonymous functions in an argument list participate in type inference and overload resolution. Veja a inferência de tipos e a 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 na 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;
}
}
A ItemList<T>
classe tem dois Sum
métodos.The ItemList<T>
class has two Sum
methods. Cada um tem um selector
argumento, que extrai o valor para somar 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 a double
e a soma resultante é, da mesma forma, um 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
.
Os Sum
métodos poderiam, por exemplo, ser usados para computar somas de 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 os Sum
métodos são aplicáveis porque a função anônima d => d. UnitCount
é compatível com 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 escolhe o primeiro Sum
método porque a conversão para Func<Detail,int>
é melhor do que a conversão para 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 invocação de orderDetails.Sum
, somente 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, a resolução de sobrecarga 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 associação dinâmicaAnonymous functions and dynamic binding
Uma função anônima não pode ser um receptor, argumento ou operando de uma operação vinculada dinamicamente.An anonymous function cannot be a receiver, argument or operand of a dynamically bound operation.
Variáveis externasOuter variables
Qualquer variável local, parâmetro de valor ou matriz de parâmetros cujo escopo inclui o lambda_expression ou anonymous_method_expression é chamado de uma 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 no 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.
Variáveis externas capturadasCaptured outer variables
Quando uma variável externa é referenciada por uma função anônima, diz-se que a variável externa foi capturada 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 do bloco ou da instrução com a qual está associado (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 a árvore de expressão ou delegado criada na função anônima se torne elegível para a 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
é capturada pela função anônima, e o tempo de vida de x
é estendido pelo menos até que o delegado retornado F
se torne qualificado para coleta de lixo (o que não ocorre até o final do 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). Como cada invocação da função anônima opera na mesma instância do 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, a variável local ou o parâmetro não é mais considerado uma variável fixa (variáveis fixas e móveis), mas, em vez disso, é considerado uma variável mó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. Portanto, qualquer unsafe
código que pega o endereço de uma variável externa capturada deve primeiro usar a 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, diferentemente de uma variável não capturada, uma variável local capturada pode ser exposta simultaneamente a 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 como instanciada quando a 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 inicializada 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 do loop resulta 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 é capturado, não há como observar exatamente com que frequência uma variável local é instanciada — como os tempos de vida das instâncias são não contíguos, é possível que cada instanciação simplesmente use 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 da 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
é movida 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 será considerada como sendo declarada 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 for alterado para capturar a própria 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;
}
somente uma instância da variável de iteração é capturada, o 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 compartilhem algumas variáveis capturadas, embora tenham instâncias separadas de outros.It is possible for anonymous function delegates to share some captured variables yet have separate instances of others. Por exemplo, se F
for 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, portanto, podem "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ônimasEvaluation of anonymous function expressions
Uma função anônima F
sempre deve ser convertida para um tipo delegate D
ou um tipo de árvore de expressão E
, seja 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 em conversões de função anônimas.This conversion determines the result of the anonymous function, as described in Anonymous function conversions.
Expressões de consultaQuery expressions
As expressões de consulta fornecem uma sintaxe de linguagem integrada para consultas que são semelhantes 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 uma from
cláusula e termina com uma select
group
cláusula or.A query expression begins with a from
clause and ends with either a select
or group
clause. A from
cláusula inicial pode ser seguida por zero ou mais from
cláusulas,, let
where
join
ou orderby
.The initial from
clause can be followed by zero or more from
, let
, where
, join
or orderby
clauses. Cada from
cláusula é um gerador que apresenta uma variável * Range _, que varia sobre 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 anteriores.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 do 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, gerando 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. A select
cláusula or final group
especifica a forma do resultado em termos das 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, uma 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
As expressões de consulta contêm um número de "palavras-chave contextuais", ou seja, 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, eles 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 ambigüidades em expressões de consulta causadas pelo uso misto desses identificadores como palavras-chave ou nomes simples, esses identificadores são considerados palavras-chave quando 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 comece 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 dentro de 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 das 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 convertidas em invocações de métodos que aderem ao 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 invocações de métodos chamados Where
,,,,,, Select
,, SelectMany
Join
GroupJoin
OrderBy
OrderByDescending
ThenBy
ThenByDescending
, GroupBy
e Cast
. Esses métodos devem ter assinaturas e tipos de resultados específicos, conforme descrito no 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 consultado ou métodos de extensão que são externos ao objeto e 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 conversão de expressões de consulta para invocações de método é um mapeamento sintático que ocorre antes que qualquer associação de tipo ou resolução de sobrecarga tenha sido 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 conversão tem a garantia de estar sintaticamente correta, mas não há garantia de que ele produza 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 tradução das expressões de consulta, as invocações de método resultantes são processadas como invocações de método regular, e isso pode, por sua vez, revelar erros, por exemplo, se os métodos não existirem, se os argumentos tiverem tipos incorretos ou se os métodos forem genéricos e a inferência de tipos falhar.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 pela aplicação repetida das seguintes traduções até que nenhuma redução adicional seja possível.A query expression is processed by repeatedly applying the following translations until no further reductions are possible. As traduções são listadas em ordem de aplicativo: cada seção pressupõe que as traduções nas seções anteriores foram executadas exaustivamente e, uma vez esgotadas, uma seção não será revisitada posteriormente 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.
A atribuição de 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 nem sempre impor essa restrição, uma vez que isso pode, às vezes, não ser possível com o esquema de tradução sintático 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 traduções injetam variáveis de intervalo com identificadores transparentes denotados pelo *
.Certain translations inject range variables with transparent identifiers denoted by *
. As propriedades especiais de identificadores transparentes são discutidas mais detalhadamente em identificadores transparentes.The special properties of transparent identifiers are discussed further in Transparent identifiers.
Cláusulas Select e GroupBy com continuaçãosSelect 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 pressupõem que as consultas não têm into
continuação.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 do 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
Uma 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 > ( )
Uma 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 as consultas não têm 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 do que éthe final translation of which is
customers.
Cast<Customer>().
Where(c => c.City == "London")
Os tipos de variável de intervalo explícitos são úteis para consultar coleções que implementam a interface não genérica IEnumerable
, mas não a IEnumerable<T>
interface genérica.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, esse seria o caso se customers
fosse do tipo ArrayList
.In the example above, this would be the case if customers
were of type ArrayList
.
Degerar expressões de consultaDegenerate 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 de degeneração é aquela que seleciona de trivial os elementos da origem.A degenerate query expression is one that trivially selects the elements of the source. Uma fase posterior da tradução remove as consultas de degeneração introduzidas por outras etapas de conversão, substituindo-as por sua fonte.A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. No entanto, é importante garantir que o resultado de uma expressão de consulta nunca seja o próprio objeto de origem, pois isso revelaria 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. Portanto, essa etapa protege as consultas de degeneração escritas 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. Em seguida, é até os implementadores do Select
e outros operadores de consulta para garantir que esses métodos nunca retornem o próprio 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.
De, Let, Where, cláusulas Join e OrderByFrom, let, where, join and orderby clauses
Uma expressão de consulta com uma segunda from
cláusula seguida de uma 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 seguida por algo diferente de uma 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 uma 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 uma 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 uma join
cláusula sem um into
seguido por uma 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 uma join
cláusula sem um into
seguido por algo diferente de uma 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 uma join
cláusula com um into
seguido por uma 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 uma join
cláusula com um into
seguido por algo diferente de uma 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 uma 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 cláusula de ordenação especificar um descending
indicador de direção, uma invocação OrderByDescending
ou ThenByDescending
será produzida 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 pressupõem que não há let
where
join
cláusulas,, ou orderby
, e não mais do que a from
cláusula inicial 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 do 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, é invisível e inacessí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 do 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, é invisível e inacessí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 do 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)
onde x
e y
são identificadores gerados pelo compilador que, de outra forma, são 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 de seleçãoSelect 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 x, a tradução é simplesmenteexcept when v is the identifier x, the translation is simply
( e )
Por exemplo,For 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 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 x, a conversã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 traduções injetam variáveis de intervalo com *identificadores transparentes _ indicados por _
.Certain translations inject range variables with *transparent identifiers _ denoted by _
. Os identificadores transparentes não são um recurso de idioma adequado; 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, as etapas de tradução adicionais 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, os identificadores transparentes têm o seguinte comportamento:In those contexts, transparent identifiers have the following behavior:
- Quando um identificador transparente ocorre 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 também estão no escopo.When a member with a transparent identifier is in scope, the members of that member are in scope as well.
- Quando um identificador transparente ocorre como um Declarador de membro em 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.
- Nas etapas de conversão descritas acima, os identificadores transparentes são sempre introduzidos junto com 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 do C# tem permissão para usar um mecanismo diferente de tipos anônimos para agrupar várias 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 os tipos anônimos são usados e mostram como os identificadores transparentes podem ser traduzidos fora.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 convertida 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 os identificadores transparentes são apagados, é 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, é invisível e inacessí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 reduzido 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 do 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 })
onde x
, y
e z
são identificadores gerados pelo compilador que, de outra forma, são 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 que os 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 convertidas em invocações de método por meio de um mapeamento sintático, os tipos têm flexibilidade considerável em 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 as funções anônimas são conversíveis 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 de expressão de consulta é mostrada 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 apropriadas entre os tipos de parâmetro e de 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éricos Func<T1,R>
e Func<T1,T2,R>
, mas também poderiam ter usado igualmente outros tipos de árvore de expressão ou de representante com as mesmas relações nos tipos de parâmetro e de 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 o C<T>
e o O<T>
que garante que os ThenBy
ThenByDescending
métodos e estejam 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 do resultado de GroupBy
--uma sequência de sequências, em que cada sequência interna tem uma Key
propriedade adicional.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 implemente a 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 atribuem um novo valor a 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 =
operador é chamado de operador de atribuição simples.The =
operator is called the simple assignment operator. Ele atribui o valor do operando direito à variável, à propriedade ou ao elemento do indexador fornecido pelo operando esquerdo.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 não pode ser um acesso de evento (exceto conforme descrito em eventos de 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 diferentes do =
operador são chamados de operadores de atribuição compostos.The assignment operators other than the =
operator are called the compound assignment operators. Esses operadores executam a operação indicada nos dois operandos e, em seguida, atribuim o valor resultante à variável, à propriedade ou ao elemento do indexador fornecido pelo operando esquerdo.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 compostos são descritos em atribuição composta.The compound assignment operators are described in Compound assignment.
Os +=
-=
operadores e com uma expressão de acesso de evento como o operando à esquerda são chamados de operadores de atribuição de eventos.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 um acesso de evento como o operando esquerdo.No other assignment operator is valid with an event access as the left operand. Os operadores de atribuição de eventos são descritos em atribuição de eventos.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 a 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 estiver no formato E.P
ou E[Ei]
onde E
tiver o tipo de tempo de compilação dynamic
, a atribuição será vinculada dinamicamente (associaçã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 abaixo ocorrerá em tempo de execução com base no tipo de tempo de execução de E
.In this case the compile-time type of the assignment expression is dynamic
, and the resolution described below will take place at run-time based on the run-time type of E
.
Em uma atribuição simples, o operando à direita deve ser uma expressão que seja conversível implicitamente no 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 direito à variável, à propriedade ou ao elemento do indexador fornecido pelo operando esquerdo.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 à esquerda.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 for um acesso de propriedade ou indexador, a propriedade ou o indexador deverá ter um set
acessador.If the left operand is a property or indexer access, the property or indexer must have a set
accessor. Se esse não for o caso, ocorrerá um erro de tempo de associação.If this is not the case, a binding-time error occurs.
O processamento em tempo de execução de uma atribuição simples do formulário x = y
consiste nas 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:Ifx
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 para o tipo dex
por meio de uma conversão implícita (conversões implícitas).y
is evaluated and, if required, converted to the type ofx
through an implicit conversion (Implicit conversions).- Se a variável fornecida pelo
x
for um elemento de matriz de um reference_type, uma verificação de tempo de execução será executada para garantir que o valor computadoy
seja compatível com a instância de matriz do quex
é um elemento.If the variable given byx
is an array element of a reference_type, a run-time check is performed to ensure that the value computed fory
is compatible with the array instance of whichx
is an element. A verificação terá sucesso sey
fornull
, ou se uma conversão de referência implícita (conversões de referência implícita) existir do tipo real da instância referenciada peloy
para o tipo de elemento real da instância de matriz que contémx
.The check succeeds ify
isnull
, or if an implicit reference conversion (Implicit reference conversions) exists from the actual type of the instance referenced byy
to the actual element type of the array instance containingx
. Caso contrário, umaSystem.ArrayTypeMismatchException
será gerada.Otherwise, aSystem.ArrayTypeMismatchException
is thrown. - O valor resultante da avaliação e da conversão de
y
é armazenado no local fornecido pela avaliação dex
.The value resulting from the evaluation and conversion ofy
is stored into the location given by the evaluation ofx
.
- Se
x
é classificado como um acesso de propriedade ou indexador:Ifx
is classified as a property or indexer access:- A expressão de instância (se
x
não forstatic
) e a lista de argumentos (sex
for um acesso de indexador) associada ax
são avaliadas e os resultados são usados naset
invocação subsequente do acessador.The instance expression (ifx
is notstatic
) and the argument list (ifx
is an indexer access) associated withx
are evaluated, and the results are used in the subsequentset
accessor invocation. y
é avaliado e, se necessário, convertido para o tipo dex
por meio de uma conversão implícita (conversões implícitas).y
is evaluated and, if required, converted to the type ofx
through an implicit conversion (Implicit conversions).- O
set
acessador dox
é invocado com o valor calculadoy
como seuvalue
argumento.Theset
accessor ofx
is invoked with the value computed fory
as itsvalue
argument.
- A expressão de instância (se
As regras de covariância de matriz (covariância de matriz) permitem que um valor de um tipo de matriz A[]
seja uma referência a uma instância de um tipo de matriz B[]
, desde que exista 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 seja 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
a última atribuição faz com que um seja System.ArrayTypeMismatchException
gerado porque uma instância do ArrayList
não pode ser armazenada 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 um indexador declarado em um struct_type é o destino de uma atribuição, a expressão de instância associada à propriedade ou ao acesso do indexador deve ser classificada 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 for 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. Devido ao acesso de membro, a mesma regra também se aplica a 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 todas inválidas, pois 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 estiver no formato E.P
ou E[Ei]
onde E
tiver o tipo de tempo de compilação dynamic
, a atribuição será vinculada dinamicamente (associaçã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 abaixo ocorrerá em tempo de execução com base no tipo de tempo de execução de E
.In this case the compile-time type of the assignment expression is dynamic
, and the resolution described below will take place at run-time based on the run-time type of E
.
Uma operação do formulário x op= y
é processada pela aplicação da resolução de sobrecarga de operador binário (resolução de sobrecarga de operador binário) como se a operação fosse gravada 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
. E, em seguida,Then,
- Se o tipo de retorno do operador selecionado for implicitamente conversível para o tipo de
x
, a operação será avaliada comox = x op y
, exceto quex
é avaliada apenas uma vez.If the return type of the selected operator is implicitly convertible to the type ofx
, the operation is evaluated asx = x op y
, except thatx
is evaluated only once. - Caso contrário, se o operador selecionado for um operador predefinido, se o tipo de retorno do operador selecionado for explicitamente conversível para o tipo de
x
e sey
for implicitamente conversível para o tipox
ou o operador for um operador de deslocamento, a operação será avaliada comox = (T)(x op y)
, em queT
é o tipo dex
, exceto quex
é 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 ofx
, and ify
is implicitly convertible to the type ofx
or the operator is a shift operator, then the operation is evaluated asx = (T)(x op y)
, whereT
is the type ofx
, except thatx
is evaluated only once. - Caso contrário, a atribuição composta é inválida e ocorre um erro de tempo de ligaçã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 quaisquer expressões constituintes do x
são temporariamente salvos e reutilizados ao executar a atribuição para o 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()
, em que A
é um método que retorna e int[]
B
e C
são métodos retornando int
, os métodos são invocados 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 indexador, a propriedade ou o indexador deve ter um 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 esse não for o caso, ocorrerá um erro de tempo de associação.If this is not the case, a binding-time error occurs.
A segunda regra acima permite x op= y
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 os operadores predefinidos possam 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
. Mesmo quando ambos os argumentos são 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 x op= y
permitido se ambos x op y
x = y
forem 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 de cada erro é que uma atribuição simples correspondente também teria sido 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 as operações de atribuição compostas dão suporte a operações levantadas.This also means that compound assignment operations support lifted operations. No exemploIn the example
int? i = 0;
i += 1; // Ok
o operador levantado +(int?,int?)
é usado.the lifted operator +(int?,int?)
is used.
Atribuição de eventoEvent assignment
Se o operando esquerdo de um +=
-=
operador or for classificado como um acesso de evento, a expressão será 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 ao evento é avaliada.The instance expression, if any, of the event access is evaluated.
- O operando à direita do
+=
-=
operador OR é avaliado e, se necessário, convertido para o tipo do operando esquerdo 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 eventos do evento é invocado, com a lista de argumentos que consiste no operando direito, após a avaliação e, se necessário, a 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 era
+=
, oadd
acessador é invocado; se o operador era-=
, oremove
acessador é invocado.If the operator was+=
, theadd
accessor is invoked; if the operator was-=
, theremove
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. Assim, uma expressão de atribuição de evento é válida somente no contexto de uma statement_expression (instruções de expressão).Thus, an event assignment expression is valid only in the context of a statement_expression (Expression statements).
ExpressionExpression
Uma expressão é uma 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
Uma constant_expression é uma expressão que pode ser totalmente 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 thenull
literal). - Referências a
const
membros de tipos de classe e struct.References toconst
members of class and struct types. - Referências a membros de tipos de enumeração.References to members of enumeration types.
- Referências a
const
parâmetros ou variáveis locaisReferences toconst
parameters or local variables - Subexpressão entre parênteses, que são expressões constantes.Parenthesized sub-expressions, which are themselves constant expressions.
- Expressões de conversão, desde que o tipo de destino seja um dos tipos listados acima.Cast expressions, provided the target type is one of the types listed above.
checked
eunchecked
expressõeschecked
andunchecked
expressions- Expressões de valor padrãoDefault value expressions
- Expressões nameofNameof expressions
- Os operadores predefinidos
+
,-
, e!
~
unários.The predefined+
,-
,!
, and~
unary operators. - Os operadores predefinidos,,,,,,,,,,,,,,,,
+
-
*
/
%
<<
>>
&
|
^
&&
||
==
!=
<
>
<=
e>=
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