ExpresionesExpressions
Una expresión es una secuencia de operadores y operandos.An expression is a sequence of operators and operands. En este capítulo se define la sintaxis, el orden de evaluación de los operandos y operadores y el significado de las expresiones.This chapter defines the syntax, order of evaluation of operands and operators, and meaning of expressions.
Clasificaciones de expresionesExpression classifications
Una expresión se clasifica de las siguientes formas:An expression is classified as one of the following:
- Un valor.A value. Todos los valores tienen un tipo asociado.Every value has an associated type.
- Una variable.A variable. Cada variable tiene un tipo asociado, es decir, el tipo declarado de la variable.Every variable has an associated type, namely the declared type of the variable.
- Espacio de nombres.A namespace. Una expresión con esta clasificación solo puede aparecer como la parte izquierda de un member_access (acceso a miembros).An expression with this classification can only appear as the left hand side of a member_access (Member access). En cualquier otro contexto, una expresión clasificada como un espacio de nombres produce un error en tiempo de compilación.In any other context, an expression classified as a namespace causes a compile-time error.
- Un tipo.A type. Una expresión con esta clasificación solo puede aparecer como el lado izquierdo de un member_access (acceso a miembros) o como un operando para el
asoperador (el operador as), elisoperador (operador is) o eltypeofoperador (el 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 theasoperator (The as operator), theisoperator (The is operator), or thetypeofoperator (The typeof operator). En cualquier otro contexto, una expresión clasificada como un tipo genera un error en tiempo de compilación.In any other context, an expression classified as a type causes a compile-time error. - Un grupo de métodos, que es un conjunto de métodos sobrecargados que resultan de una búsqueda de miembros (búsqueda de miembros).A method group, which is a set of overloaded methods resulting from a member lookup (Member lookup). Un grupo de métodos puede tener una expresión de instancia asociada y una lista de argumentos de tipo asociada.A method group may have an associated instance expression and an associated type argument list. Cuando se invoca un método de instancia, el resultado de evaluar la expresión de instancia se convierte en la instancia representada por
this(este acceso).When an instance method is invoked, the result of evaluating the instance expression becomes the instance represented bythis(This access). Se permite un grupo de métodos en un invocation_expression (expresiones de invocación), un delegate_creation_expression (expresiones de creación de delegado) y como el lado izquierdo de un operador is y se puede convertir implícitamente en un tipo de delegado compatible (conversiones 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). En cualquier otro contexto, una expresión clasificada como grupo de métodos produce un error en tiempo de compilación.In any other context, an expression classified as a method group causes a compile-time error. - Un literal null.A null literal. Una expresión con esta clasificación se puede convertir implícitamente a un tipo de referencia o a un tipo que acepta valores NULL.An expression with this classification can be implicitly converted to a reference type or nullable type.
- Una función anónima.An anonymous function. Una expresión con esta clasificación se puede convertir implícitamente en un tipo de delegado compatible o un tipo de árbol de expresión.An expression with this classification can be implicitly converted to a compatible delegate type or expression tree type.
- Un acceso de propiedad.A property access. Cada acceso de propiedad tiene un tipo asociado, es decir, el tipo de la propiedad.Every property access has an associated type, namely the type of the property. Además, un acceso de propiedad puede tener una expresión de instancia asociada.Furthermore, a property access may have an associated instance expression. Cuando se invoca un descriptor
getsetde acceso (el bloque o) de una propiedad de instancia, el resultado de evaluar la expresión de instancia se convierte en la instancia representada porthis(este acceso).When an accessor (thegetorsetblock) of an instance property access is invoked, the result of evaluating the instance expression becomes the instance represented bythis(This access). - Un acceso de evento.An event access. Cada acceso a eventos tiene un tipo asociado, es decir, el tipo del evento.Every event access has an associated type, namely the type of the event. Además, un acceso a eventos puede tener una expresión de instancia asociada.Furthermore, an event access may have an associated instance expression. Un acceso a eventos puede aparecer como el operando izquierdo de
+=los-=operadores y (asignación de eventos).An event access may appear as the left hand operand of the+=and-=operators (Event assignment). En cualquier otro contexto, una expresión clasificada como acceso de evento produce un error en tiempo de compilación.In any other context, an expression classified as an event access causes a compile-time error. - Un acceso de indexador.An indexer access. Cada acceso de indexador tiene un tipo asociado, es decir, el tipo de elemento del indexador.Every indexer access has an associated type, namely the element type of the indexer. Además, un acceso de indexador tiene una expresión de instancia asociada y una lista de argumentos asociada.Furthermore, an indexer access has an associated instance expression and an associated argument list. Cuando se invoca un descriptor
getsetde acceso (el bloque o) de un acceso de indexador, el resultado de evaluar la expresión de instancia se convierte en la instancia representada porthis(este acceso) y el resultado de evaluar la lista de argumentos se convierte en la lista de parámetros de la invocación.When an accessor (thegetorsetblock) 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. Esto sucede cuando la expresión es una invocación de un método con un tipo de valor devuelto de
void.This occurs when the expression is an invocation of a method with a return type ofvoid. Una expresión clasificada como Nothing solo es válida en el contexto de una statement_expression (instrucciones de expresión).An expression classified as nothing is only valid in the context of a statement_expression (Expression statements).
El resultado final de una expresión nunca es un espacio de nombres, tipo, grupo de métodos o acceso a eventos.The final result of an expression is never a namespace, type, method group, or event access. En su lugar, como se indicó anteriormente, estas categorías de expresiones son construcciones intermedias que solo se permiten en determinados contextos.Rather, as noted above, these categories of expressions are intermediate constructs that are only permitted in certain contexts.
Un acceso de propiedad o de indexador siempre se reclasifica como un valor realizando una invocación del descriptor de acceso get o del descriptor de acceso 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. El descriptor de acceso concreto viene determinado por el contexto de la propiedad o el acceso del indexador: Si el acceso es el destino de una asignación, se invoca al descriptor de acceso set para asignar un nuevo valor (asignación simple).The particular accessor is determined by the context of the property or indexer access: If the access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). De lo contrario, el descriptor de acceso get se invoca para obtener el valor actual (valores de las expresiones).Otherwise, the get accessor is invoked to obtain the current value (Values of expressions).
Valores de las expresionesValues of expressions
En última instancia, la mayoría de las construcciones que implican una expresión requieren que la expresión denote un valor.Most of the constructs that involve an expression ultimately require the expression to denote a value. En tales casos, si la expresión real denota un espacio de nombres, un tipo, un grupo de métodos o nada, se produce un error en tiempo de compilación.In such cases, if the actual expression denotes a namespace, a type, a method group, or nothing, a compile-time error occurs. Sin embargo, si la expresión denota un acceso de propiedad, un acceso a indexador o una variable, el valor de la propiedad, el indexador o la variable se sustituyen implícitamente: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:
- El valor de una variable es simplemente el valor almacenado actualmente en la ubicación de almacenamiento identificada por la variable.The value of a variable is simply the value currently stored in the storage location identified by the variable. Una variable se debe considerar definitivamente asignada (asignación definitiva) antes de que se pueda obtener su valor o, de lo contrario, se producirá un error en tiempo de compilación.A variable must be considered definitely assigned (Definite assignment) before its value can be obtained, or otherwise a compile-time error occurs.
- El valor de una expresión de acceso de propiedad se obtiene invocando el descriptor de acceso get de la propiedad.The value of a property access expression is obtained by invoking the get accessor of the property. Si la propiedad no tiene un descriptor de acceso get, se produce un error en tiempo de compilación.If the property has no get accessor, a compile-time error occurs. De lo contrario, se realiza una invocación de miembro de función (comprobación en tiempo de compilación de la resolución dinámica de sobrecarga) y el resultado de la invocación se convierte en el valor de la expresión de acceso de propiedad.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.
- El valor de una expresión de acceso de indexador se obtiene al invocar el descriptor de acceso get del indexador.The value of an indexer access expression is obtained by invoking the get accessor of the indexer. Si el indizador no tiene ningún descriptor de acceso get, se produce un error en tiempo de compilación.If the indexer has no get accessor, a compile-time error occurs. De lo contrario, se realiza una invocación de un miembro de función (comprobación en tiempo de compilación de la resolución dinámica de sobrecarga) con la lista de argumentos asociada a la expresión de acceso del indizador y el resultado de la invocación se convierte en el valor de la expresión de acceso del 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.
Enlaces estáticos y dinámicosStatic and Dynamic Binding
El proceso de determinar el significado de una operación basándose en el tipo o valor de las expresiones constituyentes (argumentos, operandos, receptores) a menudo se conoce como enlace.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 ejemplo, el significado de una llamada al método se determina en función del tipo del receptor y de los argumentos.For instance the meaning of a method call is determined based on the type of the receiver and arguments. El significado de un operador se determina en función del tipo de sus operandos.The meaning of an operator is determined based on the type of its operands.
En C#, el significado de una operación se suele determinar en tiempo de compilación, basándose en el tipo en tiempo de compilación de sus expresiones constituyentes.In C# the meaning of an operation is usually determined at compile-time, based on the compile-time type of its constituent expressions. Del mismo modo, si una expresión contiene un error, el compilador detecta el error y lo emite.Likewise, if an expression contains an error, the error is detected and reported by the compiler. Este enfoque se conoce como enlace estático.This approach is known as static binding.
Sin embargo, si una expresión es una expresión dinámica (es decir, tiene el tipo dynamic ), esto indica que cualquier enlace en el que participe debería basarse en su tipo en tiempo de ejecución (es decir, el tipo real del objeto que denota en tiempo de ejecución) en lugar del tipo que tiene en tiempo de compilación.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. Por consiguiente, el enlace de esta operación se aplaza hasta el momento en que se ejecuta la operación durante la ejecución del 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. Esto se conoce como enlace dinámico.This is referred to as dynamic binding.
Cuando una operación está enlazada dinámicamente, el compilador realiza poca o ninguna comprobación.When an operation is dynamically bound, little or no checking is performed by the compiler. En su lugar, si se produce un error en el enlace en tiempo de ejecución, los errores se registran como excepciones en tiempo de ejecución.Instead if the run-time binding fails, errors are reported as exceptions at run-time.
Las siguientes operaciones en C# están sujetas al enlace:The following operations in C# are subject to binding:
- Acceso a miembros:
e.MMember access:e.M - Invocación de método:
e.M(e1, ..., eN)Method invocation:e.M(e1, ..., eN) - Invocación de delegado:
e(e1, ..., eN)Delegate invocation:e(e1, ..., eN) - Acceso a elementos:
e[e1, ..., eN]Element access:e[e1, ..., eN] - Creación de objetos:
new C(e1, ..., eN)Object creation:new C(e1, ..., eN) - Operadores unarios sobrecargados:
+,-,!,~,++,--,true,falseOverloaded unary operators:+,-,!,~,++,--,true,false - Operadores binarios sobrecargados:
+,-,*,/,,,%&&&,|,||,??,^,<<,>>,==,!=,>,<,>=,<=Overloaded binary operators:+,-,*,/,%,&,&&,|,||,??,^,<<,>>,==,!=,>,<,>=,<= - Operadores de asignación:
=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=Assignment operators:=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>= - Conversiones implícitas y explícitasImplicit and explicit conversions
Cuando no hay ninguna expresión dinámica implicada, el valor predeterminado de C# es el enlace estático, lo que significa que los tipos en tiempo de compilación de las expresiones constituyentes se usan en el proceso de selección.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. Sin embargo, cuando una de las expresiones constituyentes de las operaciones enumeradas anteriormente es una expresión dinámica, la operación se enlaza dinámicamente.However, when one of the constituent expressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound.
Tiempo de enlaceBinding-time
El enlace estático se realiza en tiempo de compilación, mientras que el enlace dinámico tiene lugar en tiempo de ejecución.Static binding takes place at compile-time, whereas dynamic binding takes place at run-time. En las secciones siguientes, el término tiempo de enlace hace referencia a un tiempo de compilación o a un tiempo de ejecución, en función de cuándo tenga lugar el enlace.In the following sections, the term binding-time refers to either compile-time or run-time, depending on when the binding takes place.
En el ejemplo siguiente se muestran las nociones de enlace estático y dinámico y del tiempo de enlace: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)
Las dos primeras llamadas se enlazan estáticamente: la sobrecarga de Console.WriteLine se selecciona basándose en el tipo en tiempo de compilación de su argumento.The first two calls are statically bound: the overload of Console.WriteLine is picked based on the compile-time type of their argument. Por lo tanto, el tiempo de enlace es el tiempo de compilación.Thus, the binding-time is compile-time.
La tercera llamada está enlazada dinámicamente: la sobrecarga de Console.WriteLine se selecciona basándose en el tipo en tiempo de ejecución de su argumento.The third call is dynamically bound: the overload of Console.WriteLine is picked based on the run-time type of its argument. Esto sucede porque el argumento es una expresión dinámica: su tipo en tiempo de compilación es dynamic .This happens because the argument is a dynamic expression -- its compile-time type is dynamic. Por lo tanto, el tiempo de enlace para la tercera llamada es en tiempo de ejecución.Thus, the binding-time for the third call is run-time.
Enlace dinámicoDynamic binding
El propósito de los enlaces dinámicos es permitir que los programas de C# interactúen con objetos dinámicos, es decir, los objetos que no siguen las reglas normales del sistema de tipos de 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. Los objetos dinámicos pueden ser objetos de otros lenguajes de programación con distintos sistemas de tipos, o bien pueden ser objetos que se configuran mediante programación para implementar su propia semántica de enlace para diferentes operaciones.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.
El mecanismo por el que un objeto dinámico implementa su propia semántica es la implementación definida.The mechanism by which a dynamic object implements its own semantics is implementation defined. Una interfaz determinada, que se ha definido de nuevo en la implementación, se implementa mediante objetos dinámicos para indicar al tiempo de ejecución de C# que tienen una 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. Por lo tanto, cada vez que las operaciones en un objeto dinámico se enlazan dinámicamente, su propia semántica de enlace, en lugar de las de C# tal como se especifica en este documento, asumen el control.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.
Aunque el propósito del enlace dinámico es permitir la interoperación con objetos dinámicos, C# permite el enlace dinámico en todos los objetos, tanto si son dinámicos como si no.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. Esto permite una integración más fluida de los objetos dinámicos, ya que los resultados de las operaciones en ellos pueden no ser objetos dinámicos, pero siguen siendo un tipo desconocido para el programador en tiempo de compilación.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. Además, el enlace dinámico puede ayudar a eliminar el código basado en la reflexión propenso a errores, incluso cuando ningún objeto implicado sea de objetos dinámicos.Also dynamic binding can help eliminate error-prone reflection-based code even when no objects involved are dynamic objects.
En las secciones siguientes se describe para cada construcción del lenguaje exactamente cuando se aplica el enlace dinámico, qué comprobación del tiempo de compilación se aplica, en caso de que se aplique, y cuál es el resultado en tiempo de compilación y la clasificación de la expresión.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 expresiones constituyentesTypes of constituent expressions
Cuando una operación se enlaza estáticamente, el tipo de una expresión constituyente (por ejemplo, un receptor, un argumento, un índice o un operando) siempre se considera el tipo en tiempo de compilación de esa expresión.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.
Cuando una operación se enlaza de forma dinámica, el tipo de una expresión constituyente se determina de maneras diferentes en función del tipo en tiempo de compilación de la expresión constituyente: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:
- Se considera que una expresión constitutiva del tipo en tiempo de compilación
dynamictiene el tipo del valor real al que se evalúa la expresión en tiempo de ejecución.A constituent expression of compile-time typedynamicis considered to have the type of the actual value that the expression evaluates to at runtime - Expresión constituyente cuyo tipo en tiempo de compilación es un parámetro de tipo se considera que tiene el tipo al que está enlazado el parámetro de tipo en tiempo de ejecución.A constituent expression whose compile-time type is a type parameter is considered to have the type which the type parameter is bound to at runtime
- De lo contrario, se considera que la expresión Constituyente tiene su tipo en tiempo de compilación.Otherwise the constituent expression is considered to have its compile-time type.
OperadoresOperators
Las expresiones se construyen a partir de los operadores*operandos _ y.Expressions are constructed from operands _ and _operators*_. Los operadores de una expresión indican qué operaciones se aplican a los operandos.The operators of an expression indicate which operations to apply to the operands. Ejemplos de operadores incluyen +, -, _, / y new.Examples of operators include +, -, _, /, and new. Algunos ejemplos de operandos son literales, campos, variables locales y expresiones.Examples of operands include literals, fields, local variables, and expressions.
Hay tres tipos de operadores:There are three kinds of operators:
- Operadores unarios.Unary operators. Los operadores unarios toman un operando y usan la notación de prefijo (como
--x) o la notación de postfijo (comox++).The unary operators take one operand and use either prefix notation (such as--x) or postfix notation (such asx++). - Operadores binarios.Binary operators. Los operadores binarios toman dos operandos y todos usan la notación infija (como
x + y).The binary operators take two operands and all use infix notation (such asx + y). - Operador ternario.Ternary operator. Solo un operador ternario,
?:, existe; toma tres operandos y usa la notación de infijo (c ? x : y).Only one ternary operator,?:, exists; it takes three operands and uses infix notation (c ? x : y).
El orden de evaluación de los operadores de una expresión viene determinado por la precedencia _ and _ asociativity de los operadores (precedencia y asociatividad del operador).The order of evaluation of operators in an expression is determined by the precedence _ and _ associativity of the operators (Operator precedence and associativity).
Los operandos de una expresión se evalúan de izquierda a derecha.Operands in an expression are evaluated from left to right. Por ejemplo, en F(i) + G(i++) * H(i) , se llama al método con F el valor anterior de i , a continuación, se llama al método G con el valor anterior de i , y, por último, H se llama al método con el nuevo 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. Esto es independiente de la prioridad de operador y no está relacionada con ella.This is separate from and unrelated to operator precedence.
Algunos operadores se pueden sobrecargar.Certain operators can be overloaded. La sobrecarga de operadores permite especificar implementaciones de operador definidas por el usuario para las operaciones donde uno o ambos operandos son de una clase definida por el usuario o un tipo de estructura (sobrecarga de operadores).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).
Prioridad y asociatividad de los operadoresOperator precedence and associativity
Cuando una expresión contiene varios operadores, el *precedencia _ de los operadores controla el orden en el que se evalúan los operadores individuales.When an expression contains multiple operators, the *precedence _ of the operators controls the order in which the individual operators are evaluated. Por ejemplo, la expresión x + y _ z se evalúa como x + (y * z) porque el operador * tiene mayor precedencia que el operador binario +.For example, the expression x + y _ z is evaluated as x + (y * z) because the * operator has higher precedence than the binary + operator. La precedencia de un operador se establece mediante la definición de su producción gramatical asociada.The precedence of an operator is established by the definition of its associated grammar production. Por ejemplo, un additive_expression se compone de una secuencia de multiplicative_expression s separadas + por - operadores or, lo que permite que los operadores + y tengan - menor prioridad que los * / operadores, y % .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.
En la tabla siguiente se resumen todos los operadores en orden de prioridad, de mayor a menor:The following table summarizes all operators in order of precedence from highest to lowest:
| SecciónSection | CategoríaCategory | OperadoresOperators |
|---|---|---|
| Expresiones principalesPrimary expressions | PrincipalPrimary | x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegatex.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate |
| Operadores unariosUnary operators | UnarioUnary | + - ! ~ ++x --x (T)x+ - ! ~ ++x --x (T)x |
| Operadores aritméticosArithmetic operators | MultiplicativaMultiplicative | * / %* / % |
| Operadores aritméticosArithmetic operators | AditivaAdditive | + -+ - |
| Operadores de desplazamientoShift operators | ShiftShift | << >><< >> |
| Operadores relacionales y de prueba de tiposRelational and type-testing operators | Comprobación de tipos y relacionalRelational and type testing | < > <= >= is as< > <= >= is as |
| Operadores relacionales y de prueba de tiposRelational and type-testing operators | IgualdadEquality | == !=== != |
| Operadores lógicosLogical operators | Y lógicoLogical AND | & |
| Operadores lógicosLogical operators | XOR lógicoLogical XOR | ^ |
| Operadores lógicosLogical operators | O lógicoLogical OR | | |
| Operadores lógicos condicionalesConditional logical operators | AND condicionalConditional AND | && |
| Operadores lógicos condicionalesConditional logical operators | OR condicionalConditional OR | || |
| Operador de uso combinado de NULLThe null coalescing operator | Uso combinado de NULLNull coalescing | ?? |
| Operador condicionalConditional operator | CondicionalConditional | ?: |
| Operadores de asignación, expresiones de función anónimasAssignment operators, Anonymous function expressions | Asignación y expresión lambdaAssignment and lambda expression | = *= /= %= += -= <<= >>= &= ^= |= =>= *= /= %= += -= <<= >>= &= ^= |= => |
Cuando un operando se encuentra entre dos operadores con la misma precedencia, la asociatividad de los operadores controla el orden en que se realizan las operaciones: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:
- Excepto en el caso de los operadores de asignación y el operador de uso combinado de NULL, todos los operadores binarios son asociativos a la izquierda, lo que significa que las operaciones se realizan de izquierda a derecha.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 ejemplo,
x + y + zse evalúa como(x + y) + z.For example,x + y + zis evaluated as(x + y) + z. - Los operadores de asignación, el operador de uso combinado de NULL y el operador condicional (
?:) son asociativos a la derecha, lo que significa que las operaciones se realizan de derecha a izquierda.The assignment operators, the null coalescing operator and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. Por ejemplo,x = y = zse evalúa comox = (y = z).For example,x = y = zis evaluated asx = (y = z).
La precedencia y la asociatividad pueden controlarse mediante paréntesis.Precedence and associativity can be controlled using parentheses. Por ejemplo, x + y * z primero multiplica y por z y luego suma el resultado a x, pero (x + y) * z primero suma x y y y luego multiplica el 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 operadoresOperator overloading
Todos los operadores unarios y binarios tienen implementaciones predefinidas que están disponibles automáticamente en cualquier expresión.All unary and binary operators have predefined implementations that are automatically available in any expression. Además de las implementaciones predefinidas, las implementaciones definidas por el usuario se pueden introducir incluyendo operator declaraciones en clases y Structs (operadores).In addition to the predefined implementations, user-defined implementations can be introduced by including operator declarations in classes and structs (Operators). Las implementaciones de operador definidas por el usuario siempre tienen prioridad sobre las implementaciones de operadores predefinidas: solo cuando no existan implementaciones de operadores definidos por el usuario aplicables, se tendrán en cuenta las implementaciones de operadores predefinidas, como se describe en resolución de sobrecargas de operador unario y resolución de sobrecarga de operadores binarios.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.
Los operadores unarios sobrecargables son:The overloadable unary operators are:
+ - ! ~ ++ -- true false
Aunque true y false no se utilizan explícitamente en expresiones (y, por consiguiente, no se incluyen en la tabla de precedencia en la precedencia y asociatividadde los operadores), se consideran operadores porque se invocan en varios contextos de expresión: Expresiones booleanas (Expresiones booleanas) y expresiones que implican al operador condicional (operador condicional) y operadores lógicos condicionales (operadores lógicos condicionales)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).
Los operadores binarios sobrecargables son:The overloadable binary operators are:
+ - * / % & | ^ << >> == != > < >= <=
Solo se pueden sobrecargar los operadores enumerados anteriormente.Only the operators listed above can be overloaded. En concreto, no es posible sobrecargar el acceso a miembros, la invocación de métodos o los = && operadores,,,,,,,,,,, || ?? ?: => checked unchecked new typeof default as y is .In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, as, and is operators.
Cuando se sobrecarga un operador binario, el operador de asignación correspondiente, si lo hay, también se sobrecarga de modo implícito.When a binary operator is overloaded, the corresponding assignment operator, if any, is also implicitly overloaded. Por ejemplo, una sobrecarga del operador * también es una sobrecarga del operador *= .For example, an overload of operator * is also an overload of operator *=. Esto se describe con más detalle en asignación compuesta.This is described further in Compound assignment. Tenga en cuenta que el operador de asignación ( = ) no se puede sobrecargar.Note that the assignment operator itself (=) cannot be overloaded. Una asignación siempre realiza una copia simple de bits de un valor en una variable.An assignment always performs a simple bit-wise copy of a value into a variable.
Las operaciones de conversión, como (T)x , se sobrecargan proporcionando conversiones definidas por el usuario (conversiones definidas por el usuario).Cast operations, such as (T)x, are overloaded by providing user-defined conversions (User-defined conversions).
El acceso a elementos, como a[x] , no se considera un operador sobrecargable.Element access, such as a[x], is not considered an overloadable operator. En su lugar, se admite la indexación definida por el usuario a través de indexadores (indizadores).Instead, user-defined indexing is supported through indexers (Indexers).
En las expresiones, se hace referencia a los operadores mediante la notación de operador y, en las declaraciones, se hace referencia a los operadores mediante la notación funcional.In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. En la tabla siguiente se muestra la relación entre el operador y las notaciones funcionales para los operadores unarios y binarios.The following table shows the relationship between operator and functional notations for unary and binary operators. En la primera entrada, OP denota cualquier operador de prefijo unario sobrecargable.In the first entry, op denotes any overloadable unary prefix operator. En la segunda entrada, OP denota los operadores y postfijo unarios ++ -- .In the second entry, op denotes the unary postfix ++ and -- operators. En la tercera entrada, OP denota cualquier operador binario sobrecargable.In the third entry, op denotes any overloadable binary operator.
| Notación de operadorOperator notation | Notación funcionalFunctional notation |
|---|---|
op x |
operator op(x) |
x op |
operator op(x) |
x op y |
operator op(x,y) |
Las declaraciones de operador definidas por el usuario siempre requieren que al menos uno de los parámetros sea del tipo de clase o estructura que contiene la declaración de 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. Por lo tanto, no es posible que un operador definido por el usuario tenga la misma firma que un operador predefinido.Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.
Las declaraciones de operador definidas por el usuario no pueden modificar la sintaxis, la precedencia o la asociatividad de un operador.User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. Por ejemplo, el / operador siempre es un operador binario, siempre tiene el nivel de prioridad especificado en precedencia y asociatividadde los operadores y siempre es asociativo a la izquierda.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.
Aunque es posible que un operador definido por el usuario realice cualquier cálculo, se desaconsejan las implementaciones que generan resultados distintos de los que se esperaban de forma intuitiva.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 ejemplo, una implementación de operator == debería comparar los dos operandos para determinar si son iguales y devolver un bool resultado adecuado.For example, an implementation of operator == should compare the two operands for equality and return an appropriate bool result.
Las descripciones de operadores individuales en expresiones primarias a través de operadores lógicos condicionales especifican las implementaciones predefinidas de los operadores y cualquier regla adicional que se aplique 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. En las descripciones se usa la *resolución de sobrecargas del operador unario***, la _resolución de sobrecarga del operador binario*, y _ valores de promoción *, las definiciones de que se encuentran en las secciones siguientes.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.
Resolución de sobrecarga del operador unarioUnary operator overload resolution
Una operación con el formato op x o x op , donde op es un operador unario sobrecargable y x es una expresión de tipo X , se procesa de la siguiente manera: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:
- El conjunto de operadores candidatos definidos por el usuario que proporciona
Xpara la operaciónoperator op(x)se determina mediante las reglas de los operadores candidatos definidospor el usuario.The set of candidate user-defined operators provided byXfor the operationoperator op(x)is determined using the rules of Candidate user-defined operators. - Si el conjunto de operadores definidos por el usuario candidatos no está vacío, se convierte en el conjunto de operadores candidatos para la operación.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. De lo contrario, las implementaciones unarias predefinidas
operator op, incluidas sus formas de elevación, se convierten en el conjunto de operadores candidatos para la operación.Otherwise, the predefined unaryoperator opimplementations, including their lifted forms, become the set of candidate operators for the operation. Las implementaciones predefinidas de un operador determinado se especifican en la descripción del operador (expresiones primarias y operadores unarios).The predefined implementations of a given operator are specified in the description of the operator (Primary expressions and Unary operators). - Las reglas de resolución de sobrecarga de la resolución de sobrecarga se aplican al conjunto de operadores candidatos para seleccionar el mejor operador con respecto a la lista de argumentos
(x), y este operador se convierte en el resultado del proceso de resolución 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. Si la resolución de sobrecarga no selecciona un solo operador mejor, se produce un error en tiempo de enlace.If overload resolution fails to select a single best operator, a binding-time error occurs.
Resolución de sobrecarga del operador binarioBinary operator overload resolution
Una operación con el formato x op y , donde op es un operador binario sobrecargable, x es una expresión de tipo X y y es una expresión de tipo Y , que se procesa de la siguiente manera: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:
- Se determina el conjunto de operadores candidatos definidos por el usuario que proporciona
XyYpara la operaciónoperator op(x,y).The set of candidate user-defined operators provided byXandYfor the operationoperator op(x,y)is determined. El conjunto consta de la Unión de los operadores candidatos proporcionados porXy los operadores candidatos proporcionados por, cada uno de los cuales seYdetermina mediante las reglas de los operadores candidatos definidospor el usuario.The set consists of the union of the candidate operators provided byXand the candidate operators provided byY, each determined using the rules of Candidate user-defined operators. SiXyYson del mismo tipo, o siXyYse derivan de un tipo base común, los operadores candidatos compartidos solo se producen en el conjunto combinado una vez.IfXandYare the same type, or ifXandYare derived from a common base type, then shared candidate operators only occur in the combined set once. - Si el conjunto de operadores definidos por el usuario candidatos no está vacío, se convierte en el conjunto de operadores candidatos para la operación.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. De lo contrario, las implementaciones binarias predefinidas
operator op, incluidas sus formas de elevación, se convierten en el conjunto de operadores candidatos para la operación.Otherwise, the predefined binaryoperator opimplementations, including their lifted forms, become the set of candidate operators for the operation. Las implementaciones predefinidas de un operador determinado se especifican en la descripción del operador (operadores aritméticos a través de operadores lógicos condicionales).The predefined implementations of a given operator are specified in the description of the operator (Arithmetic operators through Conditional logical operators). En el caso de los operadores de enumeración y delegado predefinidos, los únicos operadores considerados son los definidos por un tipo de delegado o de enumeración que es el tipo en tiempo de enlace de uno de los 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. - Las reglas de resolución de sobrecarga de la resolución de sobrecarga se aplican al conjunto de operadores candidatos para seleccionar el mejor operador con respecto a la lista de argumentos
(x,y), y este operador se convierte en el resultado del proceso de resolución 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. Si la resolución de sobrecarga no selecciona un solo operador mejor, se produce un error en tiempo de enlace.If overload resolution fails to select a single best operator, a binding-time error occurs.
Operadores candidatos definidos por el usuarioCandidate user-defined operators
Dado un tipo T y una operación operator op(A) , donde op es un operador sobrecargable y A es una lista de argumentos, el conjunto de operadores definidos por el usuario candidatos que proporciona T for operator op(A) se determina de la manera siguiente: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 el tipo
T0.Determine the typeT0. SiTes un tipo que acepta valores NULL,T0es su tipo subyacente, de lo contrario,T0es igual aT.IfTis a nullable type,T0is its underlying type, otherwiseT0is equal toT. - Para todas las
operator opdeclaraciones deT0y todas las formas de elevación de estos operadores, si al menos un operador es aplicable (miembro de función aplicable) con respecto a la lista de argumentosA, el conjunto de operadores candidatos está formado por todos los operadores aplicables enT0.For alloperator opdeclarations inT0and 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. - De lo contrario, si
T0esobject, el conjunto de operadores candidatos está vacío.Otherwise, ifT0isobject, the set of candidate operators is empty. - De lo contrario, el conjunto de operadores candidatos proporcionado por
T0es el conjunto de operadores candidatos proporcionado por la clase base directa deT0, o la clase base efectiva deT0siT0es un parámetro de tipo.Otherwise, the set of candidate operators provided byT0is the set of candidate operators provided by the direct base class ofT0, or the effective base class ofT0ifT0is a type parameter.
Promociones numéricasNumeric promotions
La promoción numérica consiste en realizar automáticamente determinadas conversiones implícitas de los operandos de los operadores binarios y unarios predefinidos.Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. La promoción numérica no es un mecanismo distinto, sino un efecto de aplicar la resolución de sobrecarga a los operadores predefinidos.Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. La promoción numérica específicamente no afecta a la evaluación de operadores definidos por el usuario, aunque se pueden implementar operadores definidos por el usuario para mostrar efectos similares.Numeric promotion specifically does not affect evaluation of user-defined operators, although user-defined operators can be implemented to exhibit similar effects.
Como ejemplo de promoción numérica, tenga en cuenta las implementaciones predefinidas del * operador binario: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);
Cuando se aplican las reglas de resolución de sobrecarga (resolución de sobrecarga) a este conjunto de operadores, el efecto es seleccionar el primero de los operadores para los que existen conversiones implícitas desde los 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 ejemplo, para la operación b * s , donde b es byte y s es short , la resolución de sobrecarga selecciona operator *(int,int) como el mejor 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. Por lo tanto, el efecto es que b y s se convierten en y int el tipo del resultado es int .Thus, the effect is that b and s are converted to int, and the type of the result is int. Del mismo modo, para la operación i * d , donde i es int y d es double , la resolución de sobrecarga selecciona operator *(double,double) como el mejor 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.
Promociones numéricas unariasUnary numeric promotions
La promoción numérica unaria se produce para los operandos de los + - operadores unarios predefinidos, y ~ .Unary numeric promotion occurs for the operands of the predefined +, -, and ~ unary operators. La promoción numérica unaria simplemente consiste en convertir operandos de tipo sbyte , byte , short , ushort o char en tipo int .Unary numeric promotion simply consists of converting operands of type sbyte, byte, short, ushort, or char to type int. Además, para el operador unario - , la promoción numérica unaria convierte operandos de tipo uint al tipo long .Additionally, for the unary - operator, unary numeric promotion converts operands of type uint to type long.
Promociones numéricas binariasBinary numeric promotions
La promoción numérica binaria se produce para los operandos de los + - * / % & | ^ == != > < >= <= operadores binarios predefinidos,,,,,,,,,,,, y.Binary numeric promotion occurs for the operands of the predefined +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. La promoción numérica binaria convierte implícitamente ambos operandos en un tipo común que, en el caso de los operadores no relacionales, también se convierte en el tipo de resultado de la operación.Binary numeric promotion implicitly converts both operands to a common type which, in case of the non-relational operators, also becomes the result type of the operation. La promoción numérica binaria consiste en aplicar las siguientes reglas, en el orden en que aparecen aquí:Binary numeric promotion consists of applying the following rules, in the order they appear here:
- Si alguno de los operandos es de tipo
decimal, el otro operando se convierte al tipodecimal, o se produce un error en tiempo de enlace si el otro operando es de tipofloatodouble.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 typefloatordouble. - De lo contrario, si alguno de los operandos es de tipo
double, el otro operando se convierte al tipodouble.Otherwise, if either operand is of typedouble, the other operand is converted to typedouble. - De lo contrario, si alguno de los operandos es de tipo
float, el otro operando se convierte al tipofloat.Otherwise, if either operand is of typefloat, the other operand is converted to typefloat. - De lo contrario, si alguno de los operandos es de tipo
ulong, el otro operando se convierte al tipoulong, o se produce un error en tiempo de enlace si el otro operando es de tiposbyte,short,intolong.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. - De lo contrario, si alguno de los operandos es de tipo
long, el otro operando se convierte al tipolong.Otherwise, if either operand is of typelong, the other operand is converted to typelong. - De lo contrario, si alguno de los operandos es de tipo
uinty el otro operando es de tiposbyte,shortoint, ambos operandos se convierten al tipolong.Otherwise, if either operand is of typeuintand the other operand is of typesbyte,short, orint, both operands are converted to typelong. - De lo contrario, si alguno de los operandos es de tipo
uint, el otro operando se convierte al tipouint.Otherwise, if either operand is of typeuint, the other operand is converted to typeuint. - De lo contrario, ambos operandos se convierten al tipo
int.Otherwise, both operands are converted to typeint.
Tenga en cuenta que la primera regla no permite ninguna operación que mezcle el decimal tipo con double los float tipos y.Note that the first rule disallows any operations that mix the decimal type with the double and float types. La regla sigue el hecho de que no hay conversiones implícitas entre el decimal tipo y los double float tipos y.The rule follows from the fact that there are no implicit conversions between the decimal type and the double and float types.
Tenga en cuenta también que no es posible que un operando sea de tipo ulong cuando el otro operando es de un tipo entero con signo.Also note that it is not possible for an operand to be of type ulong when the other operand is of a signed integral type. La razón es que no existe ningún tipo entero que pueda representar el intervalo completo de ulong , así como los tipos enteros con signo.The reason is that no integral type exists that can represent the full range of ulong as well as the signed integral types.
En los dos casos anteriores, se puede usar una expresión de conversión para convertir explícitamente un operando en un tipo que sea compatible con el otro 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.
En el ejemploIn the example
decimal AddPercent(decimal x, double percent) {
return x * (1.0 + percent / 100.0);
}
se produce un error en tiempo de enlace porque decimal no se puede multiplicar por double .a binding-time error occurs because a decimal cannot be multiplied by a double. El error se resuelve convirtiendo explícitamente el segundo operando en decimal , como se indica a continuación: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 de elevaciónLifted operators
Los operadores de elevación permiten a los operadores predefinidos y definidos por el usuario que operan en tipos de valor que no aceptan valores NULL usarse también con formas que aceptan valores NULL de esos 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. Los operadores de elevación se construyen a partir de operadores predefinidos y definidos por el usuario que cumplen ciertos requisitos, como se describe a continuación:Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:
Para los operadores unariosFor the unary operators
+ ++ - -- ! ~existe una forma de elevación de un operador si el operando y los tipos de resultado son tipos de valor que no aceptan valores NULL.a lifted form of an operator exists if the operand and result types are both non-nullable value types. La forma de elevación se construye agregando un único
?modificador al operando y a los tipos de resultado.The lifted form is constructed by adding a single?modifier to the operand and result types. El operador de elevación genera un valor NULL si el operando es NULL.The lifted operator produces a null value if the operand is null. De lo contrario, el operador de elevación desencapsula el operando, aplica el operador subyacente y ajusta el resultado.Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.Para los operadores binariosFor the binary operators
+ - * / % & | ^ << >>existe una forma de elevación de un operador si el operando y los tipos de resultado son todos tipos de valor que no aceptan valores NULL.a lifted form of an operator exists if the operand and result types are all non-nullable value types. La forma de elevación se construye agregando un único
?modificador a cada operando y tipo de resultado.The lifted form is constructed by adding a single?modifier to each operand and result type. El operador de elevación genera un valor NULL si uno o los dos operandos son NULL (una excepción son los&|operadores y delbool?tipo, como se describe en operadores lógicos booleanos).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). De lo contrario, el operador de elevación desencapsula los operandos, aplica el operador subyacente y ajusta el resultado.Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.Para los operadores de igualdadFor the equality operators
== !=existe una forma de elevación de un operador si los tipos de operando son tipos de valor que no aceptan valores NULL y si el tipo de resultado es
bool.a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type isbool. La forma de elevación se construye agregando un único?modificador a cada tipo de operando.The lifted form is constructed by adding a single?modifier to each operand type. El operador de elevación considera que dos valores NULL son iguales y un valor NULL es distinto de cualquier valor distinto de NULL.The lifted operator considers two null values equal, and a null value unequal to any non-null value. Si ambos operandos no son NULL, el operador de elevación desencapsula los operandos y aplica el operador subyacente para generar elboolresultado.If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce theboolresult.Para los operadores relacionalesFor the relational operators
< > <= >=existe una forma de elevación de un operador si los tipos de operando son tipos de valor que no aceptan valores NULL y si el tipo de resultado es
bool.a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type isbool. La forma de elevación se construye agregando un único?modificador a cada tipo de operando.The lifted form is constructed by adding a single?modifier to each operand type. El operador de elevación produce el valorfalsesi uno o los dos operandos son NULL.The lifted operator produces the valuefalseif one or both operands are null. De lo contrario, el operador de elevación desencapsula los operandos y aplica el operador subyacente para generar elboolresultado.Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce theboolresult.
Búsqueda de miembrosMember lookup
Una búsqueda de miembros es el proceso por el que se determina el significado de un nombre en el contexto de un tipo.A member lookup is the process whereby the meaning of a name in the context of a type is determined. Una búsqueda de miembros se puede producir como parte de la evaluación de una simple_name (nombres simples) o un member_access (acceso a miembros) en una expresión.A member lookup can occur as part of evaluating a simple_name (Simple names) or a member_access (Member access) in an expression. Si el simple_name o member_access se produce como primary_expression de un invocation_expression (invocaciones de método), se dice que el miembro se invoca.If the simple_name or member_access occurs as the primary_expression of an invocation_expression (Method invocations), the member is said to be invoked.
Si un miembro es un método o un evento, o si es una constante, un campo o una propiedad de un tipo de delegado (delegados) o del tipo dynamic (el tipo dinámico), se dice que el miembro es invocable.If a member is a method or event, or if it is a constant, field or property of either a delegate type (Delegates) or the type dynamic (The dynamic type), then the member is said to be invocable.
La búsqueda de miembros considera no solo el nombre de un miembro, sino también el número de parámetros de tipo que tiene el miembro y si el miembro es accesible.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. En lo que respecta a la búsqueda de miembros, los métodos genéricos y los tipos genéricos anidados tienen el número de parámetros de tipo indicado en sus declaraciones respectivas y todos los demás miembros tienen parámetros de tipo cero.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.
Una búsqueda de miembro de un nombre N con K parámetros de tipo en un tipo T se procesa de la siguiente manera:A member lookup of a name N with K type parameters in a type T is processed as follows:
- En primer lugar, se determina un conjunto de miembros accesibles denominados
N:First, a set of accessible members namedNis determined:- Si
Tes un parámetro de tipo, el conjunto es la Unión de los conjuntos de miembros accesibles denominadosNen cada uno de los tipos especificados como restricción principal o restricción secundaria (restricciones de parámetro de tipo) paraT, junto con el conjunto de miembros accesibles denominadosNenobject.IfTis a type parameter, then the set is the union of the sets of accessible members namedNin each of the types specified as a primary constraint or secondary constraint (Type parameter constraints) forT, along with the set of accessible members namedNinobject. - De lo contrario, el conjunto se compone de todos los miembros accesibles (acceso a miembros) denominados
NenT, incluidos los miembros heredados y los miembros accesibles denominadosNenobject.Otherwise, the set consists of all accessible (Member access) members namedNinT, including inherited members and the accessible members namedNinobject. SiTes un tipo construido, el conjunto de miembros se obtiene sustituyendo los argumentos de tipo tal y como se describe en miembros de tipos construidos.IfTis a constructed type, the set of members is obtained by substituting type arguments as described in Members of constructed types. Los miembros que incluyen unoverridemodificador se excluyen del conjunto.Members that include anoverridemodifier are excluded from the set.
- Si
- Después, si
Kes cero, se quitan todos los tipos anidados cuyas declaraciones incluyen parámetros de tipo.Next, ifKis zero, all nested types whose declarations include type parameters are removed. SiKno es cero, se quitan todos los miembros con un número diferente de parámetros de tipo.IfKis not zero, all members with a different number of type parameters are removed. Tenga en cuenta que cuandoKes cero, no se quitan los métodos que tienen parámetros de tipo, ya que el proceso de inferencia de tipos (inferencia de tipos) podría inferir los argumentos de tipo.Note that whenKis zero, methods having type parameters are not removed, since the type inference process (Type inference) might be able to infer the type arguments. - Después, si se invoca el miembro, todos los miembros que no sean de invocable se quitarán del conjunto.Next, if the member is invoked, all non-invocable members are removed from the set.
- Después, los miembros que están ocultos por otros miembros se quitan del conjunto.Next, members that are hidden by other members are removed from the set. Para cada miembro del
S.Mconjunto, dondeSes el tipo en el queMse declara el miembro, se aplican las siguientes reglas:For every memberS.Min the set, whereSis the type in which the memberMis declared, the following rules are applied:- Si
Mes una constante, un campo, una propiedad, un evento o un miembro de enumeración, todos los miembros declarados en un tipo base deSse quitan del conjunto.IfMis a constant, field, property, event, or enumeration member, then all members declared in a base type ofSare removed from the set. - Si
Mes una declaración de tipos, todos los tipos que no sean declarados en un tipo base deSse quitan del conjunto y todas las declaraciones de tipos con el mismo número de parámetros de tipoMdeclarados en un tipo base deSse quitan del conjunto.IfMis a type declaration, then all non-types declared in a base type ofSare removed from the set, and all type declarations with the same number of type parameters asMdeclared in a base type ofSare removed from the set. - Si
Mes un método, todos los miembros que no sean de método declarados en un tipo base deSse quitan del conjunto.IfMis a method, then all non-method members declared in a base type ofSare removed from the set.
- Si
- Después, los miembros de interfaz que están ocultos por miembros de clase se quitan del conjunto.Next, interface members that are hidden by class members are removed from the set. Este paso solo tiene efecto si
Tes un parámetro de tipo yTtiene una clase base efectiva distinta deobjecty un conjunto de interfaces efectivo que no está vacío (restricciones de parámetro de tipo).This step only has an effect ifTis a type parameter andThas both an effective base class other thanobjectand a non-empty effective interface set (Type parameter constraints). Para cada miembro delS.Mconjunto, dondeSes el tipo en el que se declara el miembroM, se aplican las reglas siguientes siSes una declaración de clase distinta deobject:For every memberS.Min the set, whereSis the type in which the memberMis declared, the following rules are applied ifSis a class declaration other thanobject:- Si
Mes una constante, un campo, una propiedad, un evento, un miembro de enumeración o una declaración de tipos, todos los miembros declarados en una declaración de interfaz se quitan del conjunto.IfMis a constant, field, property, event, enumeration member, or type declaration, then all members declared in an interface declaration are removed from the set. - Si
Mes un método, se quitan del conjunto todos los miembros que no son de método declarados en una declaración de interfaz y todos los métodos con la misma firma queMse declaran en una declaración de interfaz se quitan del conjunto.IfMis a method, then all non-method members declared in an interface declaration are removed from the set, and all methods with the same signature asMdeclared in an interface declaration are removed from the set.
- Si
- Por último, si se han quitado los miembros ocultos, se determina el resultado de la búsqueda:Finally, having removed hidden members, the result of the lookup is determined:
- Si el conjunto está formado por un único miembro que no es un método, este miembro es el resultado de la búsqueda.If the set consists of a single member that is not a method, then this member is the result of the lookup.
- De lo contrario, si el conjunto solo contiene métodos, este grupo de métodos es el resultado de la búsqueda.Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
- De lo contrario, la búsqueda es ambigua y se produce un error en tiempo de enlace.Otherwise, the lookup is ambiguous, and a binding-time error occurs.
Para búsquedas de miembros en tipos que no sean de tipo e interfaces, y búsquedas de miembros en interfaces que son estrictamente de herencia única (cada interfaz de la cadena de herencia tiene exactamente cero o una interfaz base directa), el efecto de las reglas de búsqueda es simplemente que los miembros derivados ocultan los miembros base con el mismo nombre o signatura.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. Dichas búsquedas de herencia única nunca son ambiguas.Such single-inheritance lookups are never ambiguous. Las ambigüedades que pueden surgir en las búsquedas de miembros en interfaces de herencia múltiple se describen en acceso a miembros de interfaz.The ambiguities that can possibly arise from member lookups in multiple-inheritance interfaces are described in Interface member access.
Tipos baseBase types
En lo que respecta a la búsqueda de miembros, T se considera que un tipo tiene los siguientes tipos base:For purposes of member lookup, a type T is considered to have the following base types:
- Si
Tesobject,Tno tiene ningún tipo base.IfTisobject, thenThas no base type. - Si
Tes un enum_type, los tipos base deTson los tipos de claseSystem.Enum,System.ValueTypeyobject.IfTis an enum_type, the base types ofTare the class typesSystem.Enum,System.ValueType, andobject. - Si
Tes un struct_type, los tipos base deTson los tipos de claseSystem.ValueTypeyobject.IfTis a struct_type, the base types ofTare the class typesSystem.ValueTypeandobject. - Si
Tes un class_type, los tipos base deTson las clases base deT, incluido el tipo de claseobject.IfTis a class_type, the base types ofTare the base classes ofT, including the class typeobject. - Si
Tes un interface_type, los tipos base deTson las interfaces base deTy el tipo de claseobject.IfTis an interface_type, the base types ofTare the base interfaces ofTand the class typeobject. - Si
Tes un array_type, los tipos base deTson los tipos de claseSystem.Arrayyobject.IfTis an array_type, the base types ofTare the class typesSystem.Arrayandobject. - Si
Tes un delegate_type, los tipos base deTson los tipos de claseSystem.Delegateyobject.IfTis a delegate_type, the base types ofTare the class typesSystem.Delegateandobject.
Miembros de funciónFunction members
Los miembros de función son miembros que contienen instrucciones ejecutables.Function members are members that contain executable statements. Los miembros de función siempre son miembros de tipos y no pueden ser miembros de espacios de nombres.Function members are always members of types and cannot be members of namespaces. C# define las siguientes categorías de miembros de función:C# defines the following categories of function members:
- MétodosMethods
- PropiedadesProperties
- EventsEvents
- IndizadoresIndexers
- Operadores definidos por el usuarioUser-defined operators
- Constructores de instanciasInstance constructors
- Constructores estáticosStatic constructors
- DestructoresDestructors
A excepción de los destructores y los constructores estáticos (que no se pueden invocar explícitamente), las instrucciones contenidas en miembros de función se ejecutan a través de las invocaciones de miembros de función.Except for destructors and static constructors (which cannot be invoked explicitly), the statements contained in function members are executed through function member invocations. La sintaxis real para escribir una invocación de miembros de función depende de la categoría de miembro de función determinada.The actual syntax for writing a function member invocation depends on the particular function member category.
La lista de argumentos (listas de argumentos) de una invocación de miembros de función proporciona valores reales o referencias de variable para los parámetros del miembro de función.The argument list (Argument lists) of a function member invocation provides actual values or variable references for the parameters of the function member.
Las invocaciones de métodos genéricos pueden emplear la inferencia de tipos para determinar el conjunto de argumentos de tipo que se van a pasar al método.Invocations of generic methods may employ type inference to determine the set of type arguments to pass to the method. Este proceso se describe en inferencia de tipos.This process is described in Type inference.
Las invocaciones de métodos, indizadores, operadores y constructores de instancia emplean la resolución de sobrecarga para determinar cuál de un conjunto candidato de miembros de función se va a invocar.Invocations of methods, indexers, operators and instance constructors employ overload resolution to determine which of a candidate set of function members to invoke. Este proceso se describe en resolución de sobrecarga.This process is described in Overload resolution.
Una vez que se ha identificado un miembro de función determinado en tiempo de enlace, posiblemente a través de la resolución de sobrecarga, el proceso real en tiempo de ejecución de la invocación del miembro de función se describe en la comprobación en tiempo de compilación de la resolución de sobrecarga dinámica.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.
En la tabla siguiente se resume el procesamiento que tiene lugar en construcciones que implican las seis categorías de miembros de función que se pueden invocar explícitamente.The following table summarizes the processing that takes place in constructs involving the six categories of function members that can be explicitly invoked. En la tabla,,, e x y y value indican expresiones clasificadas como variables o valores, T indica una expresión clasificada como un tipo, F es el nombre simple de un método y P es el nombre simple de una propiedad.In the table, e, x, y, and value indicate expressions classified as variables or values, T indicates an expression classified as a type, F is the simple name of a method, and P is the simple name of a property.
| ConstruirConstruct | EjemploExample | DescripciónDescription |
|---|---|---|
| Invocación de métodoMethod invocation | F(x,y) |
La resolución de sobrecarga se aplica para seleccionar el mejor método F en la clase o estructura contenedora.Overload resolution is applied to select the best method F in the containing class or struct. El método se invoca con la lista de argumentos (x,y) .The method is invoked with the argument list (x,y). Si el método no es static , la expresión de instancia es this .If the method is not static, the instance expression is this. |
T.F(x,y) |
La resolución de sobrecarga se aplica para seleccionar el mejor método F en la clase o estructura T .Overload resolution is applied to select the best method F in the class or struct T. Se produce un error en tiempo de enlace si el método no es static .A binding-time error occurs if the method is not static. El método se invoca con la lista de argumentos (x,y) .The method is invoked with the argument list (x,y). |
|
e.F(x,y) |
La resolución de sobrecarga se aplica para seleccionar el mejor método F en la clase, estructura o interfaz dada por el 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. Se produce un error en tiempo de enlace si el método es static .A binding-time error occurs if the method is static. El método se invoca con la expresión de instancia e y la lista de argumentos (x,y) .The method is invoked with the instance expression e and the argument list (x,y). |
|
| Property AccessProperty access | P |
getSe invoca el descriptor de acceso de la propiedad P en la clase o estructura contenedora.The get accessor of the property P in the containing class or struct is invoked. Se produce un error en tiempo de compilación si P es de solo escritura.A compile-time error occurs if P is write-only. Si P no es static , la expresión de instancia es this .If P is not static, the instance expression is this. |
P = value |
El set descriptor de acceso de la propiedad P en la clase o estructura contenedora se invoca con la lista de argumentos (value) .The set accessor of the property P in the containing class or struct is invoked with the argument list (value). Se produce un error en tiempo de compilación si P es de solo lectura.A compile-time error occurs if P is read-only. Si P no es static , la expresión de instancia es this .If P is not static, the instance expression is this. |
|
T.P |
getSe invoca el descriptor de acceso de la propiedad P en la clase o estructura T .The get accessor of the property P in the class or struct T is invoked. Se produce un error en tiempo de compilación si P no es static o si P es de solo escritura.A compile-time error occurs if P is not static or if P is write-only. |
|
T.P = value |
El set descriptor de acceso de la propiedad P de la clase o struct T se invoca con la lista de argumentos (value) .The set accessor of the property P in the class or struct T is invoked with the argument list (value). Se produce un error en tiempo de compilación si P no es static o si P es de solo lectura.A compile-time error occurs if P is not static or if P is read-only. |
|
e.P |
El get descriptor de acceso de la propiedad P en la clase, estructura o interfaz proporcionada por el tipo de e se invoca con la expresión de instancia 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. Se produce un error en tiempo de enlace si P es static o si P es de solo escritura.A binding-time error occurs if P is static or if P is write-only. |
|
e.P = value |
El set descriptor de acceso de la propiedad P en la clase, estructura o interfaz proporcionada por el tipo de e se invoca con la expresión de instancia e y la 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). Se produce un error en tiempo de enlace si P es static o si P es de solo lectura.A binding-time error occurs if P is static or if P is read-only. |
|
| Acceso a eventosEvent access | E += value |
addSe invoca el descriptor de acceso del evento E en la clase o estructura contenedora.The add accessor of the event E in the containing class or struct is invoked. Si E no es static, la expresión de instancia es this .If E is not static, the instance expression is this. |
E -= value |
removeSe invoca el descriptor de acceso del evento E en la clase o estructura contenedora.The remove accessor of the event E in the containing class or struct is invoked. Si E no es static, la expresión de instancia es this .If E is not static, the instance expression is this. |
|
T.E += value |
addSe invoca el descriptor de acceso del evento E en la clase o estructura T .The add accessor of the event E in the class or struct T is invoked. Se produce un error en tiempo de enlace si E no es estático.A binding-time error occurs if E is not static. |
|
T.E -= value |
removeSe invoca el descriptor de acceso del evento E en la clase o estructura T .The remove accessor of the event E in the class or struct T is invoked. Se produce un error en tiempo de enlace si E no es estático.A binding-time error occurs if E is not static. |
|
e.E += value |
El add descriptor de acceso del evento E en la clase, estructura o interfaz proporcionada por el tipo de e se invoca con la expresión de instancia 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. Se produce un error en tiempo de enlace si E es estático.A binding-time error occurs if E is static. |
|
e.E -= value |
El remove descriptor de acceso del evento E en la clase, estructura o interfaz proporcionada por el tipo de e se invoca con la expresión de instancia 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. Se produce un error en tiempo de enlace si E es estático.A binding-time error occurs if E is static. |
|
| Acceso a indizadorIndexer access | e[x,y] |
La resolución de sobrecarga se aplica para seleccionar el mejor indexador en la clase, estructura o interfaz dada por el tipo de e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. El get descriptor de acceso del indizador se invoca con la expresión de instancia e y la lista de argumentos (x,y) .The get accessor of the indexer is invoked with the instance expression e and the argument list (x,y). Se produce un error en tiempo de enlace si el indizador es de solo escritura.A binding-time error occurs if the indexer is write-only. |
e[x,y] = value |
La resolución de sobrecarga se aplica para seleccionar el mejor indexador en la clase, estructura o interfaz dada por el tipo de e .Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. El set descriptor de acceso del indizador se invoca con la expresión de instancia e y la 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). Se produce un error en tiempo de enlace si el indizador es de solo lectura.A binding-time error occurs if the indexer is read-only. |
|
| Invocación de operadorOperator invocation | -x |
La resolución de sobrecarga se aplica para seleccionar el mejor operador unario en la clase o estructura dada por el tipo de x .Overload resolution is applied to select the best unary operator in the class or struct given by the type of x. El operador seleccionado se invoca con la lista de argumentos (x) .The selected operator is invoked with the argument list (x). |
x + y |
La resolución de sobrecarga se aplica para seleccionar el mejor operador binario en las clases o Structs que proporcionan los tipos de x y y .Overload resolution is applied to select the best binary operator in the classes or structs given by the types of x and y. El operador seleccionado se invoca con la lista de argumentos (x,y) .The selected operator is invoked with the argument list (x,y). |
|
| Invocación del constructor de instanciaInstance constructor invocation | new T(x,y) |
La resolución de sobrecarga se aplica para seleccionar el mejor constructor de instancia en la clase o estructura T .Overload resolution is applied to select the best instance constructor in the class or struct T. El constructor de instancia se invoca con la lista de argumentos (x,y) .The instance constructor is invoked with the argument list (x,y). |
Listas de argumentosArgument lists
Cada invocación de miembro de función y delegado incluye una lista de argumentos que proporciona valores reales o referencias de variable para los parámetros del miembro de función.Every function member and delegate invocation includes an argument list which provides actual values or variable references for the parameters of the function member. La sintaxis para especificar la lista de argumentos de una invocación de miembros de función depende de la categoría de miembros de función:The syntax for specifying the argument list of a function member invocation depends on the function member category:
- En el caso de los constructores de instancias, los métodos, los indizadores y los delegados, los argumentos se especifican como un argument_list, como se describe a continuación.For instance constructors, methods, indexers and delegates, the arguments are specified as an argument_list, as described below. En el caso de los indizadores, al invocar el
setdescriptor de acceso, la lista de argumentos incluye también la expresión especificada como operando derecho del operador de asignación.For indexers, when invoking thesetaccessor, the argument list additionally includes the expression specified as the right operand of the assignment operator. - En el caso de las propiedades, la lista de argumentos está vacía al invocar el
getdescriptor de acceso y se compone de la expresión especificada como operando derecho del operador de asignación al invocar elsetdescriptor de acceso.For properties, the argument list is empty when invoking thegetaccessor, and consists of the expression specified as the right operand of the assignment operator when invoking thesetaccessor. - En el caso de los eventos, la lista de argumentos se compone de la expresión especificada como operando derecho del
+=-=operador o.For events, the argument list consists of the expression specified as the right operand of the+=or-=operator. - En el caso de los operadores definidos por el usuario, la lista de argumentos se compone del operando único del operador unario o de los dos operandos del operador binario.For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator.
Los argumentos de las propiedades (propiedades), los eventos (eventos) y los operadores definidos por el usuario (operadores) siempre se pasan 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). Los argumentos de los indizadores (indizadores) siempre se pasan como parámetros de valor (parámetros de valor) o como matrices de parámetros (matrices deparámetros).The arguments of indexers (Indexers) are always passed as value parameters (Value parameters) or parameter arrays (Parameter arrays). Los parámetros de referencia y de salida no se admiten para estas categorías de miembros de función.Reference and output parameters are not supported for these categories of function members.
Los argumentos de una invocación de constructor de instancia, método, indexador o delegado se especifican como un 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
;
Una argument_list está formada por uno o más argumentos, separados por comas.An argument_list consists of one or more argument s, separated by commas. Cada argumento consta de un argument_name opcional seguido de un argument_value.Each argument consists of an optional argument_name followed by an argument_value. Un argumento con un argument_name se conoce como un argumento *con nombre, mientras que un argumento * sin un argument_name es un 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_. Es un error que un argumento posicional aparezca después de un argumento con nombre en un _argument_list *.It is an error for a positional argument to appear after a named argument in an _argument_list*.
El argument_value puede adoptar uno de los siguientes formatos:The argument_value can take one of the following forms:
- Una expresión, que indica que el argumento se pasa como parámetro de valor (parámetros de valor).An expression, indicating that the argument is passed as a value parameter (Value parameters).
- Palabra clave
refseguida de un variable_reference (referencias de variable), que indica que el argumento se pasa como parámetro de referencia (parámetros de referencia).The keywordreffollowed by a variable_reference (Variable references), indicating that the argument is passed as a reference parameter (Reference parameters). Una variable debe estar asignada definitivamente (asignación definitiva) antes de que se pueda pasar como un parámetro de referencia.A variable must be definitely assigned (Definite assignment) before it can be passed as a reference parameter. Palabra claveoutseguida de un variable_reference (referencias de variable), que indica que el argumento se pasa como parámetro de salida (parámetros de salida).The keywordoutfollowed by a variable_reference (Variable references), indicating that the argument is passed as an output parameter (Output parameters). Una variable se considera asignada definitivamente (asignación definitiva) después de una invocación de miembro de función en la que se pasa la variable como parámetro de salida.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 correspondientesCorresponding parameters
Para cada argumento de una lista de argumentos debe haber un parámetro correspondiente en el miembro de función o el delegado que se va a invocar.For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.
La lista de parámetros que se utiliza en lo siguiente se determina de la siguiente manera:The parameter list used in the following is determined as follows:
- En el caso de los métodos virtuales y los indizadores definidos en las clases, la lista de parámetros se elige de la declaración o invalidación más específica del miembro de función, empezando por el tipo estático del receptor y buscando en sus clases 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.
- En el caso de los métodos e indexadores de la interfaz, la lista de parámetros se selecciona como la definición más específica del miembro, empezando por el tipo de interfaz y buscando en las 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. Si no se encuentra ninguna lista de parámetros única, se construye una lista de parámetros con nombres inaccesibles y ningún parámetro opcional, de modo que las invocaciones no pueden usar parámetros con nombre u omitir argumentos opcionales.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 los métodos parciales, se usa la lista de parámetros de la declaración de método parcial de definición.For partial methods, the parameter list of the defining partial method declaration is used.
- En el caso de todos los demás miembros de función y delegados, solo hay una lista de parámetros única, que es la que se usa.For all other function members and delegates there is only a single parameter list, which is the one used.
La posición de un argumento o parámetro se define como el número de argumentos o parámetros que lo preceden en la lista de argumentos o en la 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.
Los parámetros correspondientes para los argumentos de miembro de función se establecen de la siguiente manera:The corresponding parameters for function member arguments are established as follows:
- Argumentos en el argument_list de constructores de instancia, métodos, indizadores y delegados:Arguments in the argument_list of instance constructors, methods, indexers and delegates:
- Un argumento posicional en el que se produce un parámetro fijo en la misma posición en la lista de parámetros corresponde a ese parámetro.A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter.
- Un argumento posicional de un miembro de función con una matriz de parámetros invocada en su forma normal corresponde a la matriz de parámetros, que debe aparecer en la misma posición en la 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.
- Argumento posicional de un miembro de función con una matriz de parámetros invocada en su forma expandida, donde no se produce ningún parámetro fijo en la misma posición en la lista de parámetros, corresponde a un elemento de la 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.
- Un argumento con nombre corresponde al parámetro con el mismo nombre en la lista de parámetros.A named argument corresponds to the parameter of the same name in the parameter list.
- En el caso de los indizadores, al invocar el
setdescriptor de acceso, la expresión especificada como operando derecho del operador de asignación corresponde alvalueparámetro implícito de lasetdeclaración del descriptor de acceso.For indexers, when invoking thesetaccessor, the expression specified as the right operand of the assignment operator corresponds to the implicitvalueparameter of thesetaccessor declaration.
- En el caso de las propiedades, al invocar el
getdescriptor de acceso no hay ningún argumento.For properties, when invoking thegetaccessor there are no arguments. Al invocar elsetdescriptor de acceso, la expresión especificada como operando derecho del operador de asignación corresponde alvalueparámetro implícito de lasetdeclaración del descriptor de acceso.When invoking thesetaccessor, the expression specified as the right operand of the assignment operator corresponds to the implicitvalueparameter of thesetaccessor declaration. - En el caso de los operadores unarios definidos por el usuario (incluidas las conversiones), el único operando corresponde al parámetro único de la declaración del operador.For user-defined unary operators (including conversions), the single operand corresponds to the single parameter of the operator declaration.
- En el caso de los operadores binarios definidos por el usuario, el operando izquierdo corresponde al primer parámetro y el operando derecho se corresponde con el segundo parámetro de la declaración del 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.
Evaluación en tiempo de ejecución de listas de argumentosRun-time evaluation of argument lists
Durante el procesamiento en tiempo de ejecución de una invocación de miembro de función (comprobación en tiempo de compilación de la resolución dinámica de sobrecarga), las expresiones o referencias de variables de una lista de argumentos se evalúan en orden, de izquierda a derecha, de la manera siguiente: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 un parámetro de valor, se evalúa la expresión de argumento y se realiza una conversión implícita (conversiones implícitas) en el tipo de parámetro correspondiente.For a value parameter, the argument expression is evaluated and an implicit conversion (Implicit conversions) to the corresponding parameter type is performed. El valor resultante se convierte en el valor inicial del parámetro de valor en la invocación del miembro de función.The resulting value becomes the initial value of the value parameter in the function member invocation.
- Para un parámetro de referencia o de salida, se evalúa la referencia de la variable y la ubicación de almacenamiento resultante se convierte en la ubicación de almacenamiento representada por el parámetro en la invocación del miembro de función.For a reference or output parameter, the variable reference is evaluated and the resulting storage location becomes the storage location represented by the parameter in the function member invocation. Si la referencia de variable dada como parámetro de referencia o de salida es un elemento de matriz de un reference_type, se realiza una comprobación en tiempo de ejecución para asegurarse de que el tipo de elemento de la matriz es idéntico al tipo del 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. Si se produce un error en esta comprobación,
System.ArrayTypeMismatchExceptionse produce una excepción.If this check fails, aSystem.ArrayTypeMismatchExceptionis thrown.
Los métodos, indizadores y constructores de instancias pueden declarar su parámetro situado más a la derecha para que sea una matriz de parámetros (matrices de parámetros).Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array (Parameter arrays). Estos miembros de función se invocan en su forma normal o en su forma expandida, en función de cuál sea aplicable (miembro de función aplicable):Such function members are invoked either in their normal form or in their expanded form depending on which is applicable (Applicable function member):
- Cuando se invoca un miembro de función con una matriz de parámetros en su forma normal, el argumento dado para la matriz de parámetros debe ser una expresión única que se pueda convertir implícitamente (conversiones implícitas) al 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. En este caso, la matriz de parámetros actúa exactamente como un parámetro de valor.In this case, the parameter array acts precisely like a value parameter.
- Cuando se invoca un miembro de función con una matriz de parámetros en su forma expandida, la invocación debe especificar cero o más argumentos posicionales para la matriz de parámetros, donde cada argumento es una expresión que es convertible implícitamente (conversiones implícitas) al tipo de elemento de la 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. En este caso, la invocación crea una instancia del tipo de matriz de parámetros con una longitud correspondiente al número de argumentos, inicializa los elementos de la instancia de la matriz con los valores de argumento especificados y utiliza la instancia de matriz recién creada como 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.
Las expresiones de una lista de argumentos siempre se evalúan en el orden en que se escriben.The expressions of an argument list are always evaluated in the order they are written. Por lo tanto, el ejemploThus, 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++);
}
}
genera el resultadoproduces the output
x = 0, y = 1, z = 2
x = 4, y = -1, z = 3
Las reglas de covarianza de matriz (covarianza de matriz) permiten que un valor de un tipo de matriz A[] sea una referencia a una instancia de un tipo de matriz B[] , siempre que exista una conversión de referencia implícita de B a 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. Debido a estas reglas, cuando un elemento de matriz de un reference_type se pasa como parámetro de referencia o de salida, se requiere una comprobación en tiempo de ejecución para asegurarse de que el tipo de elemento real de la matriz es idéntico al del 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. En el ejemploIn 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
}
}
la segunda invocación de F hace que System.ArrayTypeMismatchException se produzca una excepción porque el tipo de elemento real de b es string y no 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.
Cuando se invoca un miembro de función con una matriz de parámetros en su forma expandida, la invocación se procesa exactamente como si se hubiera insertado una expresión de creación de matriz con un inicializador de matriz (expresiones de creación de matriz) alrededor de los 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 ejemplo, dada la declaraciónFor example, given the declaration
void F(int x, int y, params object[] args);
las siguientes invocaciones de la forma expandida del 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);
se corresponde exactamente concorrespond exactly to
F(10, 20, new object[] {});
F(10, 20, new object[] {30, 40});
F(10, 20, new object[] {1, "hello", 3.0});
En concreto, tenga en cuenta que se crea una matriz vacía cuando no hay ningún argumento dado para la matriz de parámetros.In particular, note that an empty array is created when there are zero arguments given for the parameter array.
Cuando se omiten los argumentos de un miembro de función con los parámetros opcionales correspondientes, se pasan implícitamente los argumentos predeterminados de la declaración de miembro de función.When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. Dado que siempre son constantes, su evaluación no afectará al orden de evaluación de los argumentos restantes.Because these are always constant, their evaluation will not impact the evaluation order of the remaining arguments.
Inferencia de tiposType inference
Cuando se llama a un método genérico sin especificar argumentos de tipo, un proceso de inferencia de tipos intenta deducir los argumentos de tipo de la llamada.When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. La presencia de la inferencia de tipos permite usar una sintaxis más cómoda para llamar a un método genérico y permite al programador evitar especificar información de tipos redundantes.The presence of type inference allows a more convenient syntax to be used for calling a generic method, and allows the programmer to avoid specifying redundant type information. Por ejemplo, dada la declaración del 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;
}
}
es posible invocar el Choose método sin especificar explícitamente un 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>
A través de la inferencia de tipos, los argumentos de tipo int y string se determinan a partir de los argumentos del método.Through type inference, the type arguments int and string are determined from the arguments to the method.
La inferencia de tipos se produce como parte del procesamiento en tiempo de enlace de una invocación de método (invocaciones de método) y tiene lugar antes del paso de resolución de sobrecarga de la invocación.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. Cuando se especifica un grupo de métodos determinado en una invocación de método y no se especifica ningún argumento de tipo como parte de la invocación del método, se aplica la inferencia de tipos a cada método genérico del 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. Si la inferencia de tipos se realiza correctamente, los argumentos de tipo deducido se usan para determinar los tipos de argumentos para la resolución de sobrecarga subsiguiente.If type inference succeeds, then the inferred type arguments are used to determine the types of arguments for subsequent overload resolution. Si la resolución de sobrecarga elige un método genérico como el que se va a invocar, los argumentos de tipo deducido se usan como argumentos de tipo reales para la invocación.If overload resolution chooses a generic method as the one to invoke, then the inferred type arguments are used as the actual type arguments for the invocation. Si se produce un error en la inferencia de tipos para un método determinado, ese método no participa en la resolución de sobrecarga.If type inference for a particular method fails, that method does not participate in overload resolution. El error de inferencia de tipos, en y de sí mismo, no produce un error en tiempo de enlace.The failure of type inference, in and of itself, does not cause a binding-time error. Sin embargo, a menudo se produce un error en tiempo de enlace cuando la resolución de sobrecarga no encuentra ningún método aplicable.However, it often leads to a binding-time error when overload resolution then fails to find any applicable methods.
Si el número de argumentos proporcionado es diferente del número de parámetros del método, se producirá un error inmediatamente en la inferencia.If the supplied number of arguments is different than the number of parameters in the method, then inference immediately fails. En caso contrario, supongamos que el método genérico tiene la siguiente firma:Otherwise, assume that the generic method has the following signature:
Tr M<X1,...,Xn>(T1 x1, ..., Tm xm)
Con una llamada al método de la forma M(E1...Em) , la tarea de inferencia de tipo es buscar argumentos S1...Sn de tipo únicos para cada uno de los parámetros de tipo X1...Xn , de modo que la llamada M<S1...Sn>(E1...Em) sea 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 el proceso de inferencia, cada parámetro de tipo Xi se fija en un tipo determinado Si o se desfija con un conjunto de límites asociado.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 uno de los límites es algún tipo T .Each of the bounds is some type T. Inicialmente, cada variable Xi de tipo se desfija con un conjunto vacío de límites.Initially each type variable Xi is unfixed with an empty set of bounds.
La inferencia de tipos tiene lugar en fases.Type inference takes place in phases. Cada fase intentará deducir los argumentos de tipo para obtener más variables de tipo basadas en los resultados de la fase anterior.Each phase will try to infer type arguments for more type variables based on the findings of the previous phase. La primera fase realiza algunas inferencias iniciales de límites, mientras que en la segunda fase se corrigen las variables de tipo a tipos específicos y se deducen más límites.The first phase makes some initial inferences of bounds, whereas the second phase fixes type variables to specific types and infers further bounds. Es posible que la segunda fase se repita varias veces.The second phase may have to be repeated a number of times.
Nota: La inferencia de tipos no solo tiene lugar cuando se llama a un método genérico.Note: Type inference takes place not only when a generic method is called. La inferencia de tipos para la conversión de grupos de métodos se describe en inferencia de tipos para la conversión de grupos de métodos y encontrar el mejor tipo común de un conjunto de expresiones se describe en Buscar el mejor tipo común de un conjunto de expresiones.Type inference for conversion of method groups is described in Type inference for conversion of method groups and finding the best common type of a set of expressions is described in Finding the best common type of a set of expressions.
La primera faseThe first phase
Para cada uno de los argumentos del método Ei :For each of the method arguments Ei:
- Si
Eies una función anónima, se realiza una inferencia de tipo de parámetro explícita (inferencias de tipos de parámetros explícitos) deEiaTiIfEiis an anonymous function, an explicit parameter type inference (Explicit parameter type inferences) is made fromEitoTi - De lo contrario, si
Eitiene un tipoUyxies un parámetro de valor, se realiza una inferencia de enlace inferior desdeUaTi.Otherwise, ifEihas a typeUandxiis a value parameter then a lower-bound inference is made fromUtoTi. - De lo contrario, si
Eitiene un tipoUyxies unrefoutparámetro o, se realiza una inferencia exacta desdeUaTi.Otherwise, ifEihas a typeUandxiis areforoutparameter then an exact inference is made fromUtoTi. - De lo contrario, no se realiza ninguna inferencia para este argumento.Otherwise, no inference is made for this argument.
La segunda faseThe second phase
La segunda fase continúa como sigue:The second phase proceeds as follows:
- Todas las variables de tipo
Xisin corregir que no dependen de (dependencia)Xjse corrigen (corrigiendo).All unfixed type variablesXiwhich do not depend on (Dependence) anyXjare fixed (Fixing). - Si no existe ninguna variable de tipo, se fijan todas las variables de tipo no fijas
Xipara las que se retrasen:If no such type variables exist, all unfixed type variablesXiare fixed for which all of the following hold:- Hay al menos una variable de tipo
Xjque depende deXiThere is at least one type variableXjthat depends onXi Xitiene un conjunto de límites no vacíoXihas a non-empty set of bounds
- Hay al menos una variable de tipo
- Si no existe ninguna variable de tipo y hay variables de tipo sin corregir , se produce un error en la inferencia de tipos.If no such type variables exist and there are still unfixed type variables, type inference fails.
- De lo contrario, si no existen más variables de tipo sin corregir , la inferencia de tipos se realiza correctamente.Otherwise, if no further unfixed type variables exist, type inference succeeds.
- De lo contrario, para todos los argumentos
Eicon el tipo de parámetro correspondienteTien el que los tipos de salida (tipos de salida) contienen variables de tipo sin corregirXjpero los tipos de entrada (tipos de entrada) no, una inferencia de tipo de salida (inferencias de tipo de salida) se realiza desdeEiaTi.Otherwise, for all argumentsEiwith corresponding parameter typeTiwhere the output types (Output types) contain unfixed type variablesXjbut the input types (Input types) do not, an output type inference (Output type inferences) is made fromEitoTi. A continuación, se repite la segunda fase.Then the second phase is repeated.
Tipos de entradaInput types
Si E es un grupo de métodos o una función anónima con tipos implícitos y T es un tipo de delegado o un tipo de árbol de expresión, todos los tipos de parámetro de T son tipos de entrada de tipo E 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 salidaOutput types
Si E es un grupo de métodos o una función anónima y T es un tipo de delegado o un tipo de árbol de expresión, el tipo de valor devuelto de T es un tipo de salida de E con el 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.
DependenciaDependence
Una variable de tipo sin fijo Xi depende directamente de una variable de tipo sin corregir Xj si para algún argumento Ek con tipo Tk Xj se produce en un tipo de entrada de Ek con el tipo Tk y Xi se produce en un tipo de salida de Ek con el 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.
Xjdepende de Xi Si Xj depende directamente de Xi o si Xi depende directamente de Xk y 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. Por lo tanto, "depende de" es el cierre transitivo pero no reflexivo de "depende directamente de".Thus "depends on" is the transitive but not reflexive closure of "depends directly on".
Inferencias de tipos de salidaOutput type inferences
Una inferencia de tipo de salida se realiza desde una expresión E a un tipo T de la siguiente manera:An output type inference is made from an expression E to a type T in the following way:
- Si
Ees una función anónima con el tipo de valor devuelto inferidoU(tipo de valordevuelto deducido) y es un tipo deTdelegado o un tipo de árbol de expresión con el tipo de valor devueltoTb, una inferencia de límite inferior (inferencias de límite inferior) se realiza desdeUaTb.IfEis an anonymous function with inferred return typeU(Inferred return type) andTis a delegate type or expression tree type with return typeTb, then a lower-bound inference (Lower-bound inferences) is made fromUtoTb. - De lo contrario, si
Ees un grupo de métodos yTes un tipo de delegado o de árbol de expresión con tipos de parámetroT1...Tky tipo de valor devueltoTb, y la resolución de sobrecarga deEcon los tiposT1...Tkproduce un único método con el tipo de valor devueltoU, se realiza una inferencia de enlace inferior desdeUaTb.Otherwise, ifEis a method group andTis a delegate type or expression tree type with parameter typesT1...Tkand return typeTb, and overload resolution ofEwith the typesT1...Tkyields a single method with return typeU, then a lower-bound inference is made fromUtoTb. - De lo contrario, si
Ees una expresión de tipoU, se realiza una inferencia de enlace inferior desdeUaT.Otherwise, ifEis an expression with typeU, then a lower-bound inference is made fromUtoT. - De lo contrario, no se realiza ninguna inferencia.Otherwise, no inferences are made.
Inferencias explícitas de tipos de parámetrosExplicit parameter type inferences
Una inferencia de tipo de parámetro explícita se realiza desde una expresión E a un tipo T de la siguiente manera:An explicit parameter type inference is made from an expression E to a type T in the following way:
- Si
Ees una función anónima con tipo explícito con tipos de parámetroU1...UkyTes un tipo de delegado o un tipo de árbol de expresión con tipos de parámetroV1...Vk, para cadaUise realiza una inferencia exacta (inferencias exactas) desdeUihasta elVicorrespondienteIfEis an explicitly typed anonymous function with parameter typesU1...UkandTis a delegate type or expression tree type with parameter typesV1...Vkthen for eachUian exact inference (Exact inferences) is made fromUito the correspondingVi.
Inferencias exactasExact inferences
Una inferencia exacta de un tipo U a un tipo V se realiza de la siguiente manera:An exact inference from a type U to a type V is made as follows:
Si
Ves uno de los fijosXi,Use agrega al conjunto de límites exactos paraXi.IfVis one of the unfixedXithenUis added to the set of exact bounds forXi.De lo contrario
V1...Vk,U1...Uklos conjuntos y se determinan comprobando si se aplica cualquiera de los casos siguientes:Otherwise, setsV1...VkandU1...Ukare determined by checking if any of the following cases apply:Ves un tipoV1[...]de matriz yUes un tipoU1[...]de matriz del mismo rangoVis an array typeV1[...]andUis an array typeU1[...]of the same rankVes el tipoV1?yUes el tipo.U1?Vis the typeV1?andUis the typeU1?Ves un tipo construidoC<V1...Vk>yUes un tipo construido.C<U1...Uk>Vis a constructed typeC<V1...Vk>andUis a constructed typeC<U1...Uk>
Si se aplica cualquiera de estos casos, se realiza una inferencia exacta desde cada
Uihasta el correspondienteVi.If any of these cases apply then an exact inference is made from eachUito the correspondingVi.En caso contrario, no se realiza ninguna inferencia.Otherwise no inferences are made.
Inferencias con límite inferiorLower-bound inferences
Una inferencia de límite inferior desde un tipo U a un tipo V se realiza de la siguiente manera:A lower-bound inference from a type U to a type V is made as follows:
Si
Ves uno de los desfijosXi,Use agrega al conjunto de límites inferiores paraXi.IfVis one of the unfixedXithenUis added to the set of lower bounds forXi.De lo contrario, si
Ves el tipoV1?yUes el tipoU1?, se realiza una inferencia de límite inferior desdeU1aV1.Otherwise, ifVis the typeV1?andUis the typeU1?then a lower bound inference is made fromU1toV1.De lo contrario
U1...Uk,V1...Vklos conjuntos y se determinan comprobando si se aplica cualquiera de los casos siguientes:Otherwise, setsU1...UkandV1...Vkare determined by checking if any of the following cases apply:Ves un tipoV1[...]de matriz yUes un tipoU1[...]de matriz (o un parámetro de tipo cuyo tipo base efectivo esU1[...]) del mismo rangoVis an array typeV1[...]andUis an array typeU1[...](or a type parameter whose effective base type isU1[...]) of the same rankVes uno deIEnumerable<V1>,ICollection<V1>oIList<V1>yUes un tipo de matriz unidimensionalU1[](o un parámetro de tipo cuyo tipo base efectivo esU1[])Vis one ofIEnumerable<V1>,ICollection<V1>orIList<V1>andUis a one-dimensional array typeU1[](or a type parameter whose effective base type isU1[])Ves una clase, un struct, una interfaz o un tipo de delegado construidosC<V1...Vk>y hay un tipo únicoC<U1...Uk>, de modo queU(o, siUes un parámetro de tipo, su clase base efectiva o cualquier miembro de su conjunto de interfaz efectivo) es idéntico a, hereda de (directa o indirectamente) o implementa (directa o indirectamente)C<U1...Uk>.Vis a constructed class, struct, interface or delegate typeC<V1...Vk>and there is a unique typeC<U1...Uk>such thatU(or, ifUis a type parameter, its effective base class or any member of its effective interface set) is identical to, inherits from (directly or indirectly), or implements (directly or indirectly)C<U1...Uk>.(La restricción de unicidad significa que, en la interfaz Case
C<T> {} class U: C<X>, C<Y> {}, no se realiza ninguna inferencia al deducir deUaC<T>porqueU1puede serXoY).(The "uniqueness" restriction means that in the case interfaceC<T> {} class U: C<X>, C<Y> {}, then no inference is made when inferring fromUtoC<T>becauseU1could beXorY.)
Si se aplica cualquiera de estos casos, se realiza una inferencia desde cada
Uihasta el correspondiente, como se indica a continuaciónVi:If any of these cases apply then an inference is made from eachUito the correspondingVias follows:- Si
Uino se sabe que es un tipo de referencia, se realiza una inferencia exacta .IfUiis not known to be a reference type then an exact inference is made - De lo contrario, si
Ues un tipo de matriz, se realiza una inferencia de límite inferior .Otherwise, ifUis an array type then a lower-bound inference is made - De lo contrario, si
VesC<V1...Vk>, la inferencia depende del parámetro de tipo i-ésima deC:Otherwise, ifVisC<V1...Vk>then inference depends on the i-th type parameter ofC:- Si es covariante, se realiza una inferencia de límite inferior .If it is covariant then a lower-bound inference is made.
- Si es contravariante, se realiza una inferencia enlazada en el límite superior .If it is contravariant then an upper-bound inference is made.
- Si es invariable, se realiza una inferencia exacta .If it is invariant then an exact inference is made.
De lo contrario, no se realiza ninguna inferencia.Otherwise, no inferences are made.
Inferencias de límite superiorUpper-bound inferences
Una inferencia de límite superior de un tipo U a un tipo V se realiza de la siguiente manera:An upper-bound inference from a type U to a type V is made as follows:
Si
Ves uno de los desfijosXi,Use agrega al conjunto de límites superiores paraXi.IfVis one of the unfixedXithenUis added to the set of upper bounds forXi.De lo contrario
V1...Vk,U1...Uklos conjuntos y se determinan comprobando si se aplica cualquiera de los casos siguientes:Otherwise, setsV1...VkandU1...Ukare determined by checking if any of the following cases apply:Ues un tipoU1[...]de matriz yVes un tipoV1[...]de matriz del mismo rangoUis an array typeU1[...]andVis an array typeV1[...]of the same rankUes uno deIEnumerable<Ue>,ICollection<Ue>oIList<Ue>yVes un tipo de matriz unidimensional.Ve[]Uis one ofIEnumerable<Ue>,ICollection<Ue>orIList<Ue>andVis a one-dimensional array typeVe[]Ues el tipoU1?yVes el tipo.V1?Uis the typeU1?andVis the typeV1?Ues un tipo de clase, estructura, interfaz o delegado construidoC<U1...Uk>yVes una clase, estructura, interfaz o tipo de delegado que es idéntico a, hereda de (directa o indirectamente) o implementa (directa o indirectamente) un tipo único.C<V1...Vk>Uis constructed class, struct, interface or delegate typeC<U1...Uk>andVis 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>(La restricción de unicidad significa que, si tenemos
interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}, no se realiza ninguna inferencia al deducir deC<U1>aV<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>. No se realizan inferencias deU1enX<Q>niY<Q>.)Inferences are not made fromU1to eitherX<Q>orY<Q>.)
Si se aplica cualquiera de estos casos, se realiza una inferencia desde cada
Uihasta el correspondiente, como se indica a continuaciónVi:If any of these cases apply then an inference is made from eachUito the correspondingVias follows:- Si
Uino se sabe que es un tipo de referencia, se realiza una inferencia exacta .IfUiis not known to be a reference type then an exact inference is made - De lo contrario, si
Ves un tipo de matriz, se realiza una inferencia de límite superior .Otherwise, ifVis an array type then an upper-bound inference is made - De lo contrario, si
UesC<U1...Uk>, la inferencia depende del parámetro de tipo i-ésima deC:Otherwise, ifUisC<U1...Uk>then inference depends on the i-th type parameter ofC:- Si es covariante, se realiza una inferencia enlazada en el límite superior .If it is covariant then an upper-bound inference is made.
- Si es contravariante, se realiza una inferencia de límite inferior .If it is contravariant then a lower-bound inference is made.
- Si es invariable, se realiza una inferencia exacta .If it is invariant then an exact inference is made.
De lo contrario, no se realiza ninguna inferencia.Otherwise, no inferences are made.
Corrección deFixing
Una variable de tipo sin corregir Xi con un conjunto de límites se fija de la manera siguiente:An unfixed type variable Xi with a set of bounds is fixed as follows:
- El conjunto de tipos candidatos
Ujcomienza como el conjunto de todos los tipos del conjunto de límites paraXi.The set of candidate typesUjstarts out as the set of all types in the set of bounds forXi. - A continuación, examinaremos cada límite de a
Xisu vez: para cada límite exactoUdeXitodos los tiposUjque no sean idénticos a,Use quitan del conjunto de candidatos.We then examine each bound forXiin turn: For each exact boundUofXiall typesUjwhich are not identical toUare removed from the candidate set. Para cada límite inferiorUdeXitodos los tiposUja los que no se haya quitado una conversión implícita delUconjunto de candidatos.For each lower boundUofXiall typesUjto which there is not an implicit conversion fromUare removed from the candidate set. Para cada límite superiorUdeXitodos los tiposUja partir de los cuales no se quita una conversión implícita de enUel conjunto de candidatos.For each upper boundUofXiall typesUjfrom which there is not an implicit conversion toUare removed from the candidate set. - Si entre los tipos de candidatos restantes
Ujhay un tipo únicoVdesde el que hay una conversión implícita a todos los demás tipos candidatos,Xise fija enV.If among the remaining candidate typesUjthere is a unique typeVfrom which there is an implicit conversion to all the other candidate types, thenXiis fixed toV. - De lo contrario, se produce un error en la inferencia de tipos.Otherwise, type inference fails.
Tipo de valor devuelto deducidoInferred return type
El tipo de valor devuelto deducido de una función anónima F se usa durante la inferencia de tipos y la resolución de sobrecarga.The inferred return type of an anonymous function F is used during type inference and overload resolution. El tipo de valor devuelto deducido solo se puede determinar para una función anónima en la que se conocen todos los tipos de parámetro, ya sea porque se proporcionan explícitamente, se proporcionan a través de una conversión de función anónima o se infieren durante la inferencia de tipos en una invocación de método genérico envolvente.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.
El tipo de resultado deducido se determina de la siguiente manera:The inferred result type is determined as follows:
- Si el cuerpo de
Fes una expresión que tiene un tipo, el tipo de resultado deducido deFes el tipo de esa expresión.If the body ofFis an expression that has a type, then the inferred result type ofFis the type of that expression. - Si el cuerpo de
Fes un bloque y el conjunto de expresiones de las instrucciones del bloquereturntiene un mejor tipo comúnT(encontrar el mejor tipo común de un conjunto de expresiones), el tipo de resultado deducido deFesT.If the body ofFis a block and the set of expressions in the block'sreturnstatements has a best common typeT(Finding the best common type of a set of expressions), then the inferred result type ofFisT. - De lo contrario, no se puede inferir un tipo de resultado para
F.Otherwise, a result type cannot be inferred forF.
El tipo de valor devuelto deducido se determina de la siguiente manera:The inferred return type is determined as follows:
- Si
Fes Async y el cuerpo deFes una expresión clasificada como Nothing (clasificación de expresión) o un bloque de instrucciones en el que ninguna instrucción return tiene expresiones, el tipo de valor devuelto deducido esSystem.Threading.Tasks.TaskIfFis async and the body ofFis 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 - Si
Fes Async y tiene un tipo de resultado deducidoT, el tipo de valor devuelto deducido esSystem.Threading.Tasks.Task<T>.IfFis async and has an inferred result typeT, the inferred return type isSystem.Threading.Tasks.Task<T>. - Si
Fno es asincrónico y tiene un tipo de resultado deducidoT, el tipo de valor devuelto deducido esT.IfFis non-async and has an inferred result typeT, the inferred return type isT. - De lo contrario, no se puede inferir un tipo de valor devuelto para
F.Otherwise a return type cannot be inferred forF.
Como ejemplo de inferencia de tipos que implica funciones anónimas, tenga en cuenta el Select método de extensión declarado en la System.Linq.Enumerable clase: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);
}
}
}
Suponiendo que el System.Linq espacio de nombres se importó con una using cláusula y, dada una clase Customer con una Name propiedad de tipo string , el Select método se puede usar para seleccionar los nombres de una 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);
La invocación del método de extensión (invocaciones de método de extensión) de Select se procesa rescribiendo la invocación a una invocación 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);
Dado que los argumentos de tipo no se especificaron explícitamente, se usa la inferencia de tipos para inferir los argumentos de tipo.Since type arguments were not explicitly specified, type inference is used to infer the type arguments. En primer lugar, el customers argumento está relacionado con el source parámetro, infiriendo T a Customer .First, the customers argument is related to the source parameter, inferring T to be Customer. A continuación, con el proceso de inferencia de tipos de función anónima descrito anteriormente, c se especifica el tipo Customer y la expresión c.Name está relacionada con el tipo de valor devuelto del selector parámetro, infiriendo S a 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. Por lo tanto, la invocación es equivalente aThus, the invocation is equivalent to
Sequence.Select<Customer,string>(customers, (Customer c) => c.Name)
y el resultado es de tipo IEnumerable<string> .and the result is of type IEnumerable<string>.
En el ejemplo siguiente se muestra cómo la inferencia de tipos de función anónima permite la información de tipo para "fluir" entre los argumentos de una invocación 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 el 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));
}
Inferencia de tipos para la invocación:Type inference for the invocation:
double seconds = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds);
continúa del modo siguiente: en primer lugar, el argumento "1:15:30" está relacionado con el value parámetro, X que se infiere en string .proceeds as follows: First, the argument "1:15:30" is related to the value parameter, inferring X to be string. A continuación, el parámetro de la primera función anónima, s , recibe el tipo deducido string y la expresión TimeSpan.Parse(s) está relacionada con el tipo de valor devuelto de f1 , infiriendo 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 último, el parámetro de la segunda función anónima, t , recibe el tipo deducido System.TimeSpan y la expresión t.TotalSeconds está relacionada con el tipo de valor devuelto de f2 , infiriendo 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. Por lo tanto, el resultado de la invocación es de tipo double .Thus, the result of the invocation is of type double.
Inferencia de tipos para la conversión de grupos de métodosType inference for conversion of method groups
De forma similar a las llamadas de métodos genéricos, la inferencia de tipos también se debe aplicar cuando un grupo de métodos M que contiene un método genérico se convierte en un tipo de delegado determinado D (conversiones 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 un métodoGiven a method
Tr M<X1...Xn>(T1 x1 ... Tm xm)
y el grupo M de métodos que se asigna al tipo de delegado D la tarea de inferencia de tipo es buscar argumentos de tipo para S1...Sn que la expresión:and the method group M being assigned to the delegate type D the task of type inference is to find type arguments S1...Sn so that the expression:
M<S1...Sn>
se convierte en compatible (declaraciones de delegado) con D .becomes compatible (Delegate declarations) with D.
A diferencia del algoritmo de inferencia de tipos para las llamadas de método genérico, en este caso solo hay tipos de argumento, no hay expresiones de argumento.Unlike the type inference algorithm for generic method calls, in this case there are only argument types, no argument expressions. En concreto, no hay ninguna función anónima y, por lo tanto, no es necesario que haya varias fases de inferencia.In particular, there are no anonymous functions and hence no need for multiple phases of inference.
En su lugar, todos Xi se consideran sin corregir y se realiza una inferencia de enlace inferior desde cada tipo Uj de argumento de D al tipo de parámetro correspondiente Tj de M .Instead, all Xi are considered unfixed, and a lower-bound inference is made from each argument type Uj of D to the corresponding parameter type Tj of M. Si no se encuentra ningún Xi límite, se produce un error en la inferencia de tipos.If for any of the Xi no bounds were found, type inference fails. De lo contrario, todos Xi se corrigen en los correspondientes Si , que son el resultado de la inferencia de tipos.Otherwise, all Xi are fixed to corresponding Si, which are the result of type inference.
Buscar el mejor tipo común de un conjunto de expresionesFinding the best common type of a set of expressions
En algunos casos, es necesario inferir un tipo común para un conjunto de expresiones.In some cases, a common type needs to be inferred for a set of expressions. En concreto, los tipos de elemento de matrices con tipo implícito y los tipos de valor devueltos de las funciones anónimas con cuerpos de bloque se encuentran de esta manera.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 un conjunto de expresiones, E1...Em Esta inferencia debe ser equivalente a llamar a un método.Intuitively, given a set of expressions E1...Em this inference should be equivalent to calling a method
Tr M<X>(X x1 ... X xm)
con los Ei argumentos as.with the Ei as arguments.
Más concretamente, la inferencia comienza con una variable de tipo no fija X .More precisely, the inference starts out with an unfixed type variable X. A continuación, se realizan inferencias de tipos de salida de cada Ei a X .Output type inferences are then made from each Ei to X. Por último, X es fijo y, si es correcto, el tipo resultante S es el mejor tipo común resultante para las expresiones.Finally, X is fixed and, if successful, the resulting type S is the resulting best common type for the expressions. Si no S existe, las expresiones no tienen el mejor tipo común.If no such S exists, the expressions have no best common type.
Resolución de sobrecargaOverload resolution
La resolución de sobrecarga es un mecanismo en tiempo de enlace para seleccionar el mejor miembro de función que se va a invocar a partir de una lista de argumentos y un conjunto de miembros de función candidatos.Overload resolution is a binding-time mechanism for selecting the best function member to invoke given an argument list and a set of candidate function members. La resolución de sobrecarga selecciona el miembro de función que se va a invocar en los siguientes contextos distintos dentro de C#:Overload resolution selects the function member to invoke in the following distinct contexts within C#:
- Invocación de un método denominado en un invocation_expression (invocaciones de método).Invocation of a method named in an invocation_expression (Method invocations).
- Invocación de un constructor de instancia denominado en un object_creation_expression (expresiones de creación de objetos).Invocation of an instance constructor named in an object_creation_expression (Object creation expressions).
- Invocación de un descriptor de acceso de indexador a través de un element_access (acceso a elementos).Invocation of an indexer accessor through an element_access (Element access).
- Invocación de un operador predefinido o definido por el usuario al que se hace referencia en una expresión (resolución desobrecarga del operador unario y resolución de sobrecarga del operador binario).Invocation of a predefined or user-defined operator referenced in an expression (Unary operator overload resolution and Binary operator overload resolution).
Cada uno de estos contextos define el conjunto de miembros de función candidatas y la lista de argumentos en su propia manera única, tal como se describe en detalle en las secciones mencionadas anteriormente.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 ejemplo, el conjunto de candidatos para una invocación de método no incluye métodos marcados override (búsqueda de miembros) y los métodos de una clase base no son candidatos si algún método de una clase derivada es aplicable (invocaciones 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).
Una vez identificados los miembros de la función candidata y la lista de argumentos, la selección del mejor miembro de función es la misma en todos los 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 el conjunto de miembros de función candidatos aplicables, se ubica el mejor miembro de función de ese conjunto.Given the set of applicable candidate function members, the best function member in that set is located. Si el conjunto contiene solo un miembro de función, ese miembro de función es el mejor miembro de función.If the set contains only one function member, then that function member is the best function member. De lo contrario, el mejor miembro de función es un miembro de función que es mejor que todos los demás miembros de función con respecto a la lista de argumentos determinada, siempre que cada miembro de función se compare con el resto de miembros de función mediante las reglas de un mejor miembro de función.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. Si no hay exactamente un miembro de función que sea mejor que todos los demás miembros de función, la invocación del miembro de función es ambigua y se produce un error en tiempo de enlace.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.
En las secciones siguientes se definen los significados exactos de los términos * miembro de función aplicable _ y _ mejor miembro de función *.The following sections define the exact meanings of the terms applicable function member _ and _better function member**.
Miembro de función aplicableApplicable function member
Se dice que un miembro de función es un miembro de función aplicable con respecto a una lista A de argumentos cuando se cumplen todas las condiciones siguientes: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 de
Acorresponde a un parámetro en la declaración de miembro de función tal y como se describe en los parámetros correspondientes, y cualquier parámetro para el que ningún argumento corresponde es un parámetro opcional.Each argument inAcorresponds 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 de
A, el modo de paso de parámetros del argumento (es decir, el valor,refoout) es idéntico al modo de paso de parámetros del parámetro correspondiente, yFor 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 un parámetro de valor o una matriz de parámetros, existe una conversión implícita (conversiones implícitas) del argumento al tipo del parámetro correspondiente, o bienfor 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 un
refoutparámetro o, el tipo del argumento es idéntico al tipo del parámetro correspondiente.for areforoutparameter, the type of the argument is identical to the type of the corresponding parameter. Después de All,refunoutparámetro o es un alias para el argumento pasado.After all, areforoutparameter is an alias for the argument passed.
Para un miembro de función que incluye una matriz de parámetros, si el miembro de función es aplicable a las reglas anteriores, se dice que es aplicable en su *formulario 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 _. Si un miembro de función que incluye una matriz de parámetros no es aplicable en su forma normal, el miembro de función puede ser aplicable en su forma expandida _ * * *:If a function member that includes a parameter array is not applicable in its normal form, the function member may instead be applicable in its _*expanded form**:
- La forma expandida se construye reemplazando la matriz de parámetros en la declaración de miembro de función con cero o más parámetros de valor del tipo de elemento de la matriz de parámetros de modo que el número de argumentos de la lista de argumentos
Acoincida con el 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 listAmatches the total number of parameters. SiAtiene menos argumentos que el número de parámetros fijos en la declaración de miembro de función, no se puede construir la forma expandida del miembro de función y, por tanto, no es aplicable.IfAhas 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. - De lo contrario, el formulario expandido es aplicable si para cada argumento del
Amodo de paso de parámetros del argumento es idéntico al modo de paso de parámetros del parámetro correspondiente, yOtherwise, the expanded form is applicable if for each argument inAthe parameter passing mode of the argument is identical to the parameter passing mode of the corresponding parameter, and- para un parámetro de valor fijo o un parámetro de valor creado por la expansión, existe una conversión implícita (conversiones implícitas) del tipo del argumento al tipo del parámetro correspondiente, o bienfor 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 un
refoutparámetro o, el tipo del argumento es idéntico al tipo del parámetro correspondiente.for areforoutparameter, the type of the argument is identical to the type of the corresponding parameter.
Mejor miembro de funciónBetter function member
Con el fin de determinar el mejor miembro de función, se construye una lista de argumentos con la que se ha quitado una lista que contiene solo las expresiones de argumento en el orden en que aparecen en la lista de argumentos original.For the purposes of determining the better function member, a stripped-down argument list A is constructed containing just the argument expressions themselves in the order they appear in the original argument list.
Las listas de parámetros para cada uno de los miembros de la función candidata se construyen de la siguiente manera:Parameter lists for each of the candidate function members are constructed in the following way:
- La forma expandida se utiliza si el miembro de función solo se aplica en el formulario expandido.The expanded form is used if the function member was applicable only in the expanded form.
- Los parámetros opcionales sin argumentos correspondientes se quitan de la lista de parámetrosOptional parameters with no corresponding arguments are removed from the parameter list
- Los parámetros se reordenan para que se produzcan en la misma posición que el argumento correspondiente en la lista de argumentos.The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.
Dada una lista A de argumentos con un conjunto de expresiones de argumentos {E1, E2, ..., En} y dos miembros de función aplicables Mp y Mq con tipos de parámetros {P1, P2, ..., Pn} y {Q1, Q2, ..., Qn} , Mp se define como un miembro de función mejor que Mq siGiven an argument list A with a set of argument expressions {E1, E2, ..., En} and two applicable function members Mp and Mq with parameter types {P1, P2, ..., Pn} and {Q1, Q2, ..., Qn}, Mp is defined to be a better function member than Mq if
- para cada argumento, la conversión implícita de
ExaQxno es mejor que la conversión implícita deExaPx, yfor each argument, the implicit conversion fromExtoQxis not better than the implicit conversion fromExtoPx, and - para al menos un argumento, la conversión de
ExaPxes mejor que la conversión deExaQx.for at least one argument, the conversion fromExtoPxis better than the conversion fromExtoQx.
Al realizar esta evaluación, si Mp o Mq es aplicable en su forma expandida, Px o Qx hace referencia a un parámetro en la forma expandida de la 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.
En caso de que las secuencias de tipo de parámetro {P1, P2, ..., Pn} y {Q1, Q2, ..., Qn} sean equivalentes (es decir Pi , cada una tiene una conversión de identidad en la correspondiente Qi ), se aplican las siguientes reglas de separación de desempates, en orden, para determinar el mejor miembro de función.In case the parameter type sequences {P1, P2, ..., Pn} and {Q1, Q2, ..., Qn} are equivalent (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.
- Si
Mpes un método no genérico yMqes un método genérico,Mpes mejor queMq.IfMpis a non-generic method andMqis a generic method, thenMpis better thanMq. - De lo contrario, si
Mpes aplicable en su forma normal yMqtiene unaparamsmatriz y solo es aplicable en su forma expandida,Mpes mejor queMq.Otherwise, ifMpis applicable in its normal form andMqhas aparamsarray and is applicable only in its expanded form, thenMpis better thanMq. - De lo contrario, si
Mptiene más parámetros declarados queMq,Mpes mejor queMq.Otherwise, ifMphas more declared parameters thanMq, thenMpis better thanMq. Esto puede ocurrir si ambos métodos tienenparamsmatrices y solo se pueden aplicar en sus formularios expandidos.This can occur if both methods haveparamsarrays and are applicable only in their expanded forms. - De lo contrario, si todos los parámetros de
Mptienen un argumento correspondiente, mientras que los argumentos predeterminados deben sustituirse por al menos un parámetro opcional enMq, entoncesMpes mejor queMq.Otherwise if all parameters ofMphave a corresponding argument whereas default arguments need to be substituted for at least one optional parameter inMqthenMpis better thanMq. - De lo contrario, si
Mptiene tipos de parámetro más específicos queMq, entoncesMpes mejor queMq.Otherwise, ifMphas more specific parameter types thanMq, thenMpis better thanMq. Permita{R1, R2, ..., Rn}y{S1, S2, ..., Sn}represente los tipos de parámetro sin instancia y sin expandir deMpyMq.Let{R1, R2, ..., Rn}and{S1, S2, ..., Sn}represent the uninstantiated and unexpanded parameter types ofMpandMq.Mplos tipos de parámetro de son más específicos queMqsi, para cada parámetro,Rxno es menos específico queSx, y, para al menos un parámetro,Rxes más específico queSx:Mp's parameter types are more specific thanMq's if, for each parameter,Rxis not less specific thanSx, and, for at least one parameter,Rxis more specific thanSx:- Un parámetro de tipo es menos específico que un parámetro sin tipo.A type parameter is less specific than a non-type parameter.
- De forma recursiva, un tipo construido es más específico que otro tipo construido (con el mismo número de argumentos de tipo) si al menos un argumento de tipo es más específico y ningún argumento de tipo es menos específico que el argumento de tipo correspondiente en el otro.Recursively, a constructed type is more specific than another constructed type (with the same number of type arguments) if at least one type argument is more specific and no type argument is less specific than the corresponding type argument in the other.
- Un tipo de matriz es más específico que otro tipo de matriz (con el mismo número de dimensiones) si el tipo de elemento del primero es más específico que el tipo de elemento del 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.
- De lo contrario, si un miembro es un operador no de elevación y el otro es un operador de elevación, el valor de uno no elevado es mejor.Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.
- De lo contrario, ninguno de los miembros de función es mejor.Otherwise, neither function member is better.
Mejor conversión de la expresiónBetter conversion from expression
Dada una conversión implícita C1 que convierte de una expresión E a un tipo T1 , y una conversión implícita C2 que convierte de una expresión E a un tipo T2 , C1 es una conversión mejor que C2 si E no coincide exactamente con T2 y al menos uno de los siguientes elementos: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:
Ecoincide exactamente conT1(expresión de coincidencia exacta)Eexactly matchesT1(Exactly matching Expression)T1es un destino de conversión mejor queT2(mejor destinode la conversión)T1is a better conversion target thanT2(Better conversion target)
Expresión coincidente exactamenteExactly matching Expression
Dada una expresión E y un tipo T , E coincide exactamente T si uno de los siguientes contiene:Given an expression E and a type T, E exactly matches T if one of the following holds:
Etiene un tipoSy existe una conversión de identidad deSaTEhas a typeS, and an identity conversion exists fromStoTEes una función anónima,Tes un tipo de delegadoDo un tipo de árbolExpression<D>de expresión y uno de los siguientes elementos contiene:Eis an anonymous function,Tis either a delegate typeDor an expression tree typeExpression<D>and one of the following holds:- Existe un tipo de valor devuelto deducido
XparaEen el contexto de la lista de parámetros deD(tipo de valor devuelto deducido) y existe una conversión de identidad deXen el tipo de valor devuelto deDAn inferred return typeXexists forEin the context of the parameter list ofD(Inferred return type), and an identity conversion exists fromXto the return type ofD ENo es asincrónico yDtiene un tipo de valor devueltoYoEes asincrónico yDtiene un tipo de valor devueltoTask<Y>, y una de las siguientes:EitherEis non-async andDhas a return typeYorEis async andDhas a return typeTask<Y>, and one of the following holds:- El cuerpo de
Ees una expresión que coincide exactamente conYThe body ofEis an expression that exactly matchesY - El cuerpo de
Ees un bloque de instrucciones donde cada instrucción return devuelve una expresión que coincide exactamente conYThe body ofEis a statement block where every return statement returns an expression that exactly matchesY
- El cuerpo de
- Existe un tipo de valor devuelto deducido
Mejor destino de la conversiónBetter conversion target
Dados dos tipos diferentes T1 y T2 , T1 es un mejor destino de la conversión que T2 si no existe una conversión implícita de T2 a T1 , y al menos uno de los siguientes: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:
- Una conversión implícita de
T1aT2EXISTSAn implicit conversion fromT1toT2exists T1es un tipo de delegadoD1o un tipo de árbol de expresiónExpression<D1>,T2es un tipo de delegadoD2o un tipoExpression<D2>de árbol de expresión,D1tiene un tipo de valor devueltoS1y uno de los siguientes:T1is either a delegate typeD1or an expression tree typeExpression<D1>,T2is either a delegate typeD2or an expression tree typeExpression<D2>,D1has a return typeS1and one of the following holds:D2Devuelve voidD2is void returningD2tiene un tipo de valor devueltoS2yS1es un destino de conversión mejor queS2D2has a return typeS2, andS1is a better conversion target thanS2
T1esTask<S1>,T2esTask<S2>yS1es un destino de conversión mejor queS2T1isTask<S1>,T2isTask<S2>, andS1is a better conversion target thanS2T1esS1oS1?S1, donde es un tipo entero con signo yT2es o,S2S2?dondeS2es un tipo entero sin signo.T1isS1orS1?whereS1is a signed integral type, andT2isS2orS2?whereS2is an unsigned integral type. Concretamente:Specifically:S1essbyteyS2esbyte,ushort,uintoulongS1issbyteandS2isbyte,ushort,uint, orulongS1esshortyS2esushort,uintoulongS1isshortandS2isushort,uint, orulongS1esintyS2esuint, oulongS1isintandS2isuint, orulongS1eslongyS2esulongS1islongandS2isulong
Sobrecarga en clases genéricasOverloading in generic classes
Mientras que las signaturas declaradas deben ser únicas, es posible que la sustitución de los argumentos de tipo dé como resultado firmas idénticas.While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. En tales casos, las reglas de separación de sobrecargas de la resolución de sobrecarga anterior seleccionarán el miembro más específico.In such cases, the tie-breaking rules of overload resolution above will pick the most specific member.
En los ejemplos siguientes se muestran las sobrecargas válidas y no válidas según esta regla: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);
}
Comprobación en tiempo de compilación de la resolución dinámica de sobrecargaCompile-time checking of dynamic overload resolution
Para la mayoría de las operaciones enlazadas dinámicamente, el conjunto de posibles candidatos para la resolución se desconoce en tiempo de compilación.For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. En algunos casos, sin embargo, el conjunto de candidatos se conoce en tiempo de compilación:In certain cases, however the candidate set is known at compile-time:
- Llamadas a métodos estáticos con argumentos dinámicosStatic method calls with dynamic arguments
- Llamadas al método de instancia donde el receptor no es una expresión dinámicaInstance method calls where the receiver is not a dynamic expression
- Llamadas de indexador en las que el receptor no es una expresión dinámicaIndexer calls where the receiver is not a dynamic expression
- Llamadas de constructor con argumentos dinámicosConstructor calls with dynamic arguments
En estos casos, se realiza una comprobación limitada en tiempo de compilación para cada candidato a fin de ver si alguna de ellas podría aplicarse en tiempo de ejecución. Esta comprobación consta de los siguientes pasos: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:
- Inferencia de tipos parciales: cualquier argumento de tipo que no dependa directa o indirectamente de un argumento de tipo
dynamicse deduce mediante las reglas de inferencia de tipos.Partial type inference: Any type argument that does not depend directly or indirectly on an argument of typedynamicis inferred using the rules of Type inference. Los argumentos de tipo restantes son desconocidos.The remaining type arguments are unknown. - Comprobación parcial de aplicabilidad: la aplicabilidad se comprueba según el miembro de función aplicable, pero se omiten los parámetros cuyos tipos son desconocidos.Partial applicability check: Applicability is checked according to Applicable function member, but ignoring parameters whose types are unknown.
- Si ningún candidato pasa esta prueba, se produce un error en tiempo de compilación.If no candidate passes this test, a compile-time error occurs.
Invocación de miembros de funciónFunction member invocation
En esta sección se describe el proceso que tiene lugar en tiempo de ejecución para invocar un miembro de función determinado.This section describes the process that takes place at run-time to invoke a particular function member. Se supone que un proceso de tiempo de enlace ya ha determinado el miembro determinado que se va a invocar, posiblemente aplicando la resolución de sobrecarga a un conjunto de miembros de función candidatos.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.
Con el fin de describir el proceso de invocación, los miembros de función se dividen en dos categorías:For purposes of describing the invocation process, function members are divided into two categories:
- Miembros de función estáticos.Static function members. Se trata de constructores de instancia, métodos estáticos, descriptores de acceso de propiedades estáticas y operadores definidos por el usuario.These are instance constructors, static methods, static property accessors, and user-defined operators. Los miembros de función estáticos siempre son no virtuales.Static function members are always non-virtual.
- Miembros de función de instancia.Instance function members. Son métodos de instancia, descriptores de acceso de propiedades de instancia y descriptores de acceso de indexador.These are instance methods, instance property accessors, and indexer accessors. Los miembros de la función de instancia son no virtuales o virtuales, y siempre se invocan en una instancia determinada.Instance function members are either non-virtual or virtual, and are always invoked on a particular instance. La instancia se calcula mediante una expresión de instancia y se vuelve accesible dentro del miembro de función como
this(este acceso).The instance is computed by an instance expression, and it becomes accessible within the function member asthis(This access).
El procesamiento en tiempo de ejecución de una invocación de miembro de función consta de los pasos siguientes, donde M es el miembro de función y, si M es un miembro de instancia, E es la expresión de instancia:The run-time processing of a function member invocation consists of the following steps, where M is the function member and, if M is an instance member, E is the instance expression:
Si
Mes un miembro de función estática:IfMis a static function member:- La lista de argumentos se evalúa como se describe en listas de argumentos.The argument list is evaluated as described in Argument lists.
- Se invoca a
M.Mis invoked.
Si
Mes un miembro de función de instancia declarado en una value_type:IfMis an instance function member declared in a value_type:Ese evalúa.Eis evaluated. Si esta evaluación provoca una excepción, no se ejecuta ningún paso más.If this evaluation causes an exception, then no further steps are executed.- Si
Eno está clasificado como una variable, se crea una variable local temporal deEtipo y el valor deEse asigna a esa variable.IfEis not classified as a variable, then a temporary local variable ofE's type is created and the value ofEis assigned to that variable.Ea continuación, se reclasifica como una referencia a esa variable local temporal.Eis then reclassified as a reference to that temporary local variable. La variable temporal es accesible comothisenM, pero no de otra manera.The temporary variable is accessible asthiswithinM, but not in any other way. Por lo tanto, solo cuandoEes una variable verdadera, el autor de la llamada puede observar los cambios queMrealiza enthis.Thus, only whenEis a true variable is it possible for the caller to observe the changes thatMmakes tothis. - La lista de argumentos se evalúa como se describe en listas de argumentos.The argument list is evaluated as described in Argument lists.
- Se invoca a
M.Mis invoked. La variable a la que hace referenciaEse convierte en la variable a la que hace referenciathis.The variable referenced byEbecomes the variable referenced bythis.
Si
Mes un miembro de función de instancia declarado en una reference_type:IfMis an instance function member declared in a reference_type:Ese evalúa.Eis evaluated. Si esta evaluación provoca una excepción, no se ejecuta ningún paso más.If this evaluation causes an exception, then no further steps are executed.- La lista de argumentos se evalúa como se describe en listas de argumentos.The argument list is evaluated as described in Argument lists.
- Si el tipo de
Ees un value_type, se realiza una conversión boxing (conversiones boxing) para convertirEal tipoobjectyEse considera que es de tipoobjecten los pasos siguientes.If the type ofEis a value_type, a boxing conversion (Boxing conversions) is performed to convertEto typeobject, andEis considered to be of typeobjectin the following steps. En este caso,Msolo puede ser un miembro deSystem.Object.In this case,Mcould only be a member ofSystem.Object. ESe comprueba que el valor de es válido.The value ofEis checked to be valid. Si el valor deEesnull,System.NullReferenceExceptionse produce una excepción y no se ejecuta ningún paso más.If the value ofEisnull, aSystem.NullReferenceExceptionis thrown and no further steps are executed.- Se determina la implementación del miembro de función que se va a invocar:The function member implementation to invoke is determined:
- Si el tipo de tiempo de enlace de
Ees una interfaz, el miembro de función que se va a invocar es la implementación deMproporcionada por el tipo en tiempo de ejecución de la instancia de a la que hace referenciaE.If the binding-time type ofEis an interface, the function member to invoke is the implementation ofMprovided by the run-time type of the instance referenced byE. Este miembro de función se determina aplicando las reglas de asignación de interfaz (asignación de interfaz) para determinar la implementación deMproporcionada por el tipo en tiempo de ejecución de la instancia a la que hace referenciaE.This function member is determined by applying the interface mapping rules (Interface mapping) to determine the implementation ofMprovided by the run-time type of the instance referenced byE. - De lo contrario, si
Mes un miembro de función virtual, el miembro de función que se va a invocar es la implementación deMproporcionada por el tipo en tiempo de ejecución de la instancia a la que hace referenciaE.Otherwise, ifMis a virtual function member, the function member to invoke is the implementation ofMprovided by the run-time type of the instance referenced byE. Este miembro de función se determina aplicando las reglas para determinar la implementación más derivada (métodos virtuales) deMcon respecto al tipo en tiempo de ejecución de la instancia a la que hace referenciaE.This function member is determined by applying the rules for determining the most derived implementation (Virtual methods) ofMwith respect to the run-time type of the instance referenced byE. - De lo contrario,
Mes un miembro de función no virtual y el miembro de función que se va a invocar es enMsí mismo.Otherwise,Mis a non-virtual function member, and the function member to invoke isMitself.
- Si el tipo de tiempo de enlace de
- Se invoca la implementación de miembro de función determinada en el paso anterior.The function member implementation determined in the step above is invoked. El objeto al que hace referencia
Ese convierte en el objeto al que hace referenciathis.The object referenced byEbecomes the object referenced bythis.
Invocaciones en instancias de conversión boxingInvocations on boxed instances
Un miembro de función implementado en un value_type se puede invocar a través de una instancia de conversión boxing de que value_type en las situaciones siguientes:A function member implemented in a value_type can be invoked through a boxed instance of that value_type in the following situations:
- Cuando el miembro de función es un
overridede un método heredado del tipoobjecty se invoca a través de una expresión de instancia de tipoobject.When the function member is anoverrideof a method inherited from typeobjectand is invoked through an instance expression of typeobject. - Cuando el miembro de función es una implementación de un miembro de función de interfaz y se invoca a través de una expresión de instancia de un interface_type.When the function member is an implementation of an interface function member and is invoked through an instance expression of an interface_type.
- Cuando el miembro de función se invoca a través de un delegado.When the function member is invoked through a delegate.
En estas situaciones, se considera que la instancia con conversión boxing contiene una variable del value_type y esta variable se convierte en la variable a la que hace referencia this la invocación de miembros de función.In these situations, the boxed instance is considered to contain a variable of the value_type, and this variable becomes the variable referenced by this within the function member invocation. En concreto, esto significa que cuando se invoca un miembro de función en una instancia de conversión boxing, es posible que el miembro de función modifique el valor contenido en la instancia de conversión boxing.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.
Expresiones primariasPrimary expressions
Las expresiones primarias incluyen las formas más sencillas de las expresiones.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
;
Las expresiones primarias se dividen entre array_creation_expression s y primary_no_array_creation_expression s.Primary expressions are divided between array_creation_expression s and primary_no_array_creation_expression s. Al tratar la expresión de creación de matrices de esta manera, en lugar de enumerarla junto con las otras formas de expresión simples, permite que la gramática no permita el código potencialmente confuso, comoTreating array-creation-expression in this way, rather than listing it along with the other simple expression forms, enables the grammar to disallow potentially confusing code such as
object o = new int[3][1];
que de otro modo se interpretaría comowhich would otherwise be interpreted as
object o = (new int[3])[1];
LiteralesLiterals
Un primary_expression que consta de un literal (literales) se clasifica como un valor.A primary_expression that consists of a literal (Literals) is classified as a value.
Cadenas interpoladasInterpolated strings
Un interpolated_string_expression consta de un $ signo seguido de un literal de cadena normal o textual, en el que los huecos, delimitados por { y } , escriben expresiones y especificaciones de formato.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. Una expresión de cadena interpolada es el resultado de una interpolated_string_literal que se ha dividido en tokens individuales, tal y como se describe en literales de cadena 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)+
;
El constant_expression de una interpolación debe tener una conversión implícita a int .The constant_expression in an interpolation must have an implicit conversion to int.
Un interpolated_string_expression se clasifica como un valor.An interpolated_string_expression is classified as a value. Si se convierte inmediatamente en System.IFormattable o System.FormattableString con una conversión de cadena interpolada implícita (conversiones de cadenas interpoladas implícitas), la expresión de cadena interpolada tiene ese 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. De lo contrario, tiene el tipo string .Otherwise, it has the type string.
Si el tipo de una cadena interpolada es System.IFormattable o System.FormattableString , el significado es una llamada a System.Runtime.CompilerServices.FormattableStringFactory.Create .If the type of an interpolated string is System.IFormattable or System.FormattableString, the meaning is a call to System.Runtime.CompilerServices.FormattableStringFactory.Create. Si el tipo es string , el significado de la expresión es una llamada a string.Format .If the type is string, the meaning of the expression is a call to string.Format. En ambos casos, la lista de argumentos de la llamada consta de un literal de cadena de formato con marcadores de posición para cada interpolación y un argumento para cada expresión correspondiente a los marcadores de posición.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.
El literal de cadena de formato se construye como sigue, donde N es el número de interpolaciones en el interpolated_string_expression:The format string literal is constructed as follows, where N is the number of interpolations in the interpolated_string_expression:
- Si un interpolated_regular_string_whole o un interpolated_verbatim_string_whole siguen el
$signo, el literal de cadena de formato es ese token.If an interpolated_regular_string_whole or an interpolated_verbatim_string_whole follows the$sign, then the format string literal is that token. - De lo contrario, el literal de cadena de formato consta de:Otherwise, the format string literal consists of:
- En primer lugar, interpolated_regular_string_start o interpolated_verbatim_string_startFirst the interpolated_regular_string_start or interpolated_verbatim_string_start
- A continuación, para cada número
Ide0aN-1:Then for each numberIfrom0toN-1:- La representación decimal de
IThe decimal representation ofI - Después, si la interpolación correspondiente tiene una constant_expression, una
,(coma) seguida de la representación decimal del valor de la constant_expressionThen, if the corresponding interpolation has a constant_expression, a,(comma) followed by the decimal representation of the value of the constant_expression - A continuación, el interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid o interpolated_verbatim_string_end inmediatamente después de la interpolación correspondiente.Then the interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid or interpolated_verbatim_string_end immediately following the corresponding interpolation.
- La representación decimal de
Los argumentos subsiguientes son simplemente las expresiones de las interpolaciones (si existen), en orden.The subsequent arguments are simply the expressions from the interpolations (if any), in order.
TODO: ejemplos.TODO: examples.
Nombres simplesSimple names
Un simple_name consta de un identificador, seguido opcionalmente de una 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?
;
Una simple_name tiene el formato I o el formato I<A1,...,Ak> , donde I es un identificador único y <A1,...,Ak> es un 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. Si no se especifica ningún type_argument_list , considere la posibilidad K de que sea cero.When no type_argument_list is specified, consider K to be zero. La simple_name se evalúa y se clasifica de la manera siguiente:The simple_name is evaluated and classified as follows:
Si
Kes cero y el simple_name aparece dentro de un bloque y el espacio de declaración de variable local del bloque(o el de un bloque de inclusión) contiene una variable local, un parámetro o una constante con el nombreI, el simple_name hace referencia a esa variable local, parámetro o constante y se clasifica como una variable o valor.IfKis 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.Si
Kes cero y el simple_name aparece dentro del cuerpo de una declaración de método genérico y la Declaración incluye un parámetro de tipo con el nombreI, el simple_name hace referencia a ese parámetro de tipo.IfKis 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.De lo contrario, para cada tipo de instancia
T(el tipo de instancia), empezando por el tipo de instancia de la declaración de tipo de inclusión inmediata y continuando con el tipo de instancia de cada declaración de clase o estructura envolvente (si existe):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):- Si
Kes cero y la declaración deTincluye un parámetro de tipo con el nombreI, el simple_name hace referencia a ese parámetro de tipo.IfKis zero and the declaration ofTincludes a type parameter with nameI, then the simple_name refers to that type parameter. - De lo contrario, si una búsqueda de miembro (búsqueda de miembros) de
IinTcon argumentos deKtipo produce una coincidencia:Otherwise, if a member lookup (Member lookup) ofIinTwithKtype arguments produces a match:- Si
Tes el tipo de instancia de la clase o el tipo de estructura de inclusión inmediata y la búsqueda identifica uno o más métodos, el resultado es un grupo de métodos con una expresión de instancia asociada dethis.IfTis 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. Si se especificó una lista de argumentos de tipo, se usa para llamar a un método genérico (invocaciones de método).If a type argument list was specified, it is used in calling a generic method (Method invocations). - De lo contrario, si
Tes el tipo de instancia de la clase o el tipo de estructura que se encuentra inmediatamente, si la búsqueda identifica un miembro de instancia, y si la referencia se produce dentro del cuerpo de un constructor de instancia, un método de instancia o un descriptor de acceso de instancia, el resultado es el mismo que un acceso a miembro (acceso a miembros) del formulariothis.I.Otherwise, ifTis 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. Esto solo puede ocurrir cuandoKes cero.This can only happen whenKis zero. - De lo contrario, el resultado es el mismo que un acceso a miembro (acceso a miembros) del formulario
T.IoT.I<A1,...,Ak>.Otherwise, the result is the same as a member access (Member access) of the formT.IorT.I<A1,...,Ak>. En este caso, es un error en tiempo de enlace para que el simple_name haga referencia a un miembro de instancia.In this case, it is a binding-time error for the simple_name to refer to an instance member.
- Si
- Si
De lo contrario, para cada espacio de nombres
N, empezando por el espacio de nombres en el que se produce el simple_name , continuando con cada espacio de nombres envolvente (si existe) y finalizando con el espacio de nombres global, se evalúan los pasos siguientes hasta que se encuentra una entidad: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:- Si
Kes cero yIes el nombre de un espacio de nombres enN, entonces:IfKis zero andIis the name of a namespace inN, then:- Si la ubicación donde se produce el simple_name se incluye en una declaración de espacio de nombres para
Ny la declaración del espacio de nombres contiene un extern_alias_directive o using_alias_directive que asocia el nombreIcon un espacio de nombres o un tipo, el simple_name es ambiguo y se produce un error en tiempo de compilación.If the location where the simple_name occurs is enclosed by a namespace declaration forNand the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameIwith a namespace or type, then the simple_name is ambiguous and a compile-time error occurs. - De lo contrario, el simple_name hace referencia al espacio de nombres denominado
IenN.Otherwise, the simple_name refers to the namespace namedIinN.
- Si la ubicación donde se produce el simple_name se incluye en una declaración de espacio de nombres para
- De lo contrario, si
Ncontiene un tipo accesible conIparámetros de tipo y nombreK, entonces:Otherwise, ifNcontains an accessible type having nameIandKtype parameters, then:- Si
Kes cero y la ubicación donde se produce el simple_name se incluye en una declaración de espacio de nombres paraNy la declaración del espacio de nombres contiene un extern_alias_directive o using_alias_directive que asocia el nombreIcon un espacio de nombres o un tipo, el simple_name es ambiguo y se produce un error en tiempo de compilación.IfKis zero and the location where the simple_name occurs is enclosed by a namespace declaration forNand the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameIwith a namespace or type, then the simple_name is ambiguous and a compile-time error occurs. - De lo contrario, el namespace_or_type_name hace referencia al tipo construido con los argumentos de tipo especificados.Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
- Si
- De lo contrario, si la ubicación donde se produce el simple_name se incluye en una declaración de espacio de nombres para
N:Otherwise, if the location where the simple_name occurs is enclosed by a namespace declaration forN:- Si
Kes cero y la declaración del espacio de nombres contiene un extern_alias_directive o using_alias_directive que asocia el nombreIcon un espacio de nombres o tipo importado, el simple_name hace referencia a ese espacio de nombres o tipo.IfKis zero and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameIwith an imported namespace or type, then the simple_name refers to that namespace or type. - De lo contrario, si los espacios de nombres y las declaraciones de tipos importados por using_namespace_directive s y using_static_directive s de la declaración del espacio de nombres contienen exactamente un tipo accesible o un miembro estático que no es de extensión
IKcon parámetros de tipo y nombre, el simple_name hace referencia a ese tipo o miembro construido con los argumentos de tipo especificados.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 nameIandKtype parameters, then the simple_name refers to that type or member constructed with the given type arguments. - De lo contrario, si los espacios de nombres y los tipos importados por la using_namespace_directive s de la declaración del espacio de nombres contienen más de un tipo accesible o un miembro estático de método que no es de extensión con
Iparámetros de tipo y nombreK, el simple_name es ambiguo y se produce un error.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 nameIandKtype parameters, then the simple_name is ambiguous and an error occurs.
- Si
Tenga en cuenta que todo el paso es exactamente paralelo al paso correspondiente en el procesamiento de un namespace_or_type_name (espacio de nombres y nombres 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).
- Si
De lo contrario, el simple_name es indefinido y se produce un error en tiempo de compilación.Otherwise, the simple_name is undefined and a compile-time error occurs.
Expresiones entre paréntesisParenthesized expressions
Un parenthesized_expression consta de una expresión entre paréntesis.A parenthesized_expression consists of an expression enclosed in parentheses.
parenthesized_expression
: '(' expression ')'
;
Un parenthesized_expression se evalúa evaluando la expresión entre paréntesis.A parenthesized_expression is evaluated by evaluating the expression within the parentheses. Si la expresión entre paréntesis denota un espacio de nombres o un tipo, se produce un error en tiempo de compilación.If the expression within the parentheses denotes a namespace or type, a compile-time error occurs. De lo contrario, el resultado de la parenthesized_expression es el resultado de la evaluación de la expresión contenida.Otherwise, the result of the parenthesized_expression is the result of the evaluation of the contained expression.
Acceso a miembrosMember access
Un member_access consta de un primary_expression, un predefined_type o un qualified_alias_member, seguido de un token " . ", seguido de un identificador, seguido opcionalmente de un type_argument_list.A member_access consists of a primary_expression, a predefined_type, or a qualified_alias_member, followed by a "." token, followed by an identifier, optionally followed by a type_argument_list.
member_access
: primary_expression '.' identifier type_argument_list?
| predefined_type '.' identifier type_argument_list?
| qualified_alias_member '.' identifier
;
predefined_type
: 'bool' | 'byte' | 'char' | 'decimal' | 'double' | 'float' | 'int' | 'long'
| 'object' | 'sbyte' | 'short' | 'string' | 'uint' | 'ulong' | 'ushort'
;
La qualified_alias_member producción se define en calificadores de alias del espacio de nombres.The qualified_alias_member production is defined in Namespace alias qualifiers.
Una member_access tiene el formato E.I o el formato E.I<A1, ..., Ak> , donde E es una expresión principal, I es un identificador único y <A1, ..., Ak> es un 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. Si no se especifica ningún type_argument_list , considere la posibilidad K de que sea cero.When no type_argument_list is specified, consider K to be zero.
Un member_access con un primary_expression de tipo dynamic está enlazado dinámicamente (enlace dinámico).A member_access with a primary_expression of type dynamic is dynamically bound (Dynamic binding). En este caso, el compilador clasifica el acceso a miembros como un acceso de propiedad de tipo dynamic .In this case the compiler classifies the member access as a property access of type dynamic. A continuación, se aplican las siguientes reglas para determinar el significado de la member_access en tiempo de ejecución, utilizando el tipo en tiempo de ejecución en lugar del tipo en tiempo de compilación del primary_expression.The rules below to determine the meaning of the member_access are then applied at run-time, using the run-time type instead of the compile-time type of the primary_expression. Si esta clasificación en tiempo de ejecución conduce a un grupo de métodos, el acceso a miembros debe ser el primary_expression de un invocation_expression.If this run-time classification leads to a method group, then the member access must be the primary_expression of an invocation_expression.
La member_access se evalúa y se clasifica de la manera siguiente:The member_access is evaluated and classified as follows:
- Si
Kes cero yEes un espacio de nombres yEcontiene un espacio de nombres anidado con el nombreI, el resultado es dicho espacio de nombres.IfKis zero andEis a namespace andEcontains a nested namespace with nameI, then the result is that namespace. - De lo contrario, si
Ees un espacio de nombres yEcontiene un tipo accesibleIKcon parámetros de tipo y nombre, el resultado será ese tipo construido con los argumentos de tipo especificados.Otherwise, ifEis a namespace andEcontains an accessible type having nameIandKtype parameters, then the result is that type constructed with the given type arguments. - Si
Ees un predefined_type o un primary_expression clasificado como un tipo, siEno es un parámetro de tipo y si una búsqueda de miembro (búsqueda de miembros) deIenEcon parámetros deKtipo produce una coincidencia,E.Ise evalúa y se clasifica de la manera siguiente:IfEis a predefined_type or a primary_expression classified as a type, ifEis not a type parameter, and if a member lookup (Member lookup) ofIinEwithKtype parameters produces a match, thenE.Iis evaluated and classified as follows:- Si
Iidentifica un tipo, el resultado es el tipo construido con los argumentos de tipo especificados.IfIidentifies a type, then the result is that type constructed with the given type arguments. - Si
Iidentifica uno o más métodos, el resultado es un grupo de métodos sin expresión de instancia asociada.IfIidentifies one or more methods, then the result is a method group with no associated instance expression. Si se especificó una lista de argumentos de tipo, se usa para llamar a un método genérico (invocaciones de método).If a type argument list was specified, it is used in calling a generic method (Method invocations). - Si
Iidentifica unastaticpropiedad, el resultado es un acceso de propiedad sin expresión de instancia asociada.IfIidentifies astaticproperty, then the result is a property access with no associated instance expression. - Si
Iidentifica unstaticcampo:IfIidentifies astaticfield:- Si el campo es
readonlyy la referencia se produce fuera del constructor estático de la clase o estructura en la que se declara el campo, el resultado es un valor, es decir, el valor del campo estáticoIdeE.If the field isreadonlyand 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 fieldIinE. - De lo contrario, el resultado es una variable, es decir, el campo estático
IenE.Otherwise, the result is a variable, namely the static fieldIinE.
- Si el campo es
- Si
Iidentifica unstaticevento:IfIidentifies astaticevent:- Si la referencia aparece dentro de la clase o estructura en la que se declara el evento y el evento se declaró sin event_accessor_declarations (eventos),
E.Ise procesa exactamente como siIfuera un 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.Iis processed exactly as ifIwere a static field. - De lo contrario, el resultado es un acceso de evento sin expresión de instancia asociada.Otherwise, the result is an event access with no associated instance expression.
- Si la referencia aparece dentro de la clase o estructura en la que se declara el evento y el evento se declaró sin event_accessor_declarations (eventos),
- Si
Iidentifica una constante, el resultado es un valor, es decir, el valor de dicha constante.IfIidentifies a constant, then the result is a value, namely the value of that constant. - Si
Iidentifica un miembro de enumeración, el resultado es un valor, es decir, el valor de ese miembro de la enumeración.IfIidentifies an enumeration member, then the result is a value, namely the value of that enumeration member. - De lo contrario,
E.Ies una referencia de miembro no válida y se produce un error en tiempo de compilación.Otherwise,E.Iis an invalid member reference, and a compile-time error occurs.
- Si
- Si
Ees un acceso de propiedad, un acceso de indexador, una variable o un valor, cuyo tipo esT, y una búsqueda de miembro (búsqueda de miembros) deIenTcon argumentos deKtipo produce una coincidencia,E.Ise evalúa y se clasifica de la manera siguiente:IfEis a property access, indexer access, variable, or value, the type of which isT, and a member lookup (Member lookup) ofIinTwithKtype arguments produces a match, thenE.Iis evaluated and classified as follows:- En primer lugar, si
Ees un acceso de propiedad o indizador, se obtiene el valor de la propiedad o el acceso del indexador (valores de las expresiones) yEse reclasifica como un valor.First, ifEis a property or indexer access, then the value of the property or indexer access is obtained (Values of expressions) andEis reclassified as a value. - Si
Iidentifica uno o más métodos, el resultado es un grupo de métodos con una expresión de instancia asociada deE.IfIidentifies one or more methods, then the result is a method group with an associated instance expression ofE. Si se especificó una lista de argumentos de tipo, se usa para llamar a un método genérico (invocaciones de método).If a type argument list was specified, it is used in calling a generic method (Method invocations). - Si
Iidentifica una propiedad de instancia,IfIidentifies an instance property,- Si
Eesthis,Iidentifica una propiedad implementada automáticamente (propiedades implementadas automáticamente) sin un establecedor y la referencia se produce dentro de un constructor de instancia para un tipo de clase o structT, el resultado es una variable, es decir, el campo de respaldo oculto para la propiedad automática proporcionada porIen la instancia deTproporcionada porthis.IfEisthis,Iidentifies 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 byIin the instance ofTgiven bythis. - De lo contrario, el resultado es un acceso de propiedad con una expresión de instancia asociada de
E.Otherwise, the result is a property access with an associated instance expression ofE.
- Si
- Si
Tes un class_type eIidentifica un campo de instancia de que class_type:IfTis a class_type andIidentifies an instance field of that class_type:- Si el valor de
Eesnull,System.NullReferenceExceptionse produce una excepción.If the value ofEisnull, then aSystem.NullReferenceExceptionis thrown. - De lo contrario, si el campo es
readonlyy la referencia se produce fuera de un constructor de instancia de la clase en la que se declara el campo, el resultado es un valor, es decir, el valor del campoIen el objeto al que hace referenciaE.Otherwise, if the field isreadonlyand 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 fieldIin the object referenced byE. - De lo contrario, el resultado es una variable, es decir, el campo del
Iobjeto al que hace referenciaE.Otherwise, the result is a variable, namely the fieldIin the object referenced byE.
- Si el valor de
- Si
Tes un struct_type eIidentifica un campo de instancia de que struct_type:IfTis a struct_type andIidentifies an instance field of that struct_type:- Si
Ees un valor, o si el campo esreadonlyy la referencia se produce fuera de un constructor de instancia de la estructura en la que se declara el campo, el resultado es un valor, es decir, el valor del campoIen la instancia de la estructura especificada porE.IfEis a value, or if the field isreadonlyand 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 fieldIin the struct instance given byE. - De lo contrario, el resultado es una variable, es decir, el campo
Ide la instancia de struct proporcionado porE.Otherwise, the result is a variable, namely the fieldIin the struct instance given byE.
- Si
- Si
Iidentifica un evento de instancia:IfIidentifies an instance event:- Si la referencia se produce dentro de la clase o estructura en la que se declara el evento y el evento se declaró sin event_accessor_declarations (eventos), y la referencia no se produce como el lado izquierdo de un
+=-=operador OR,E.Ise procesa exactamente como siIfuera un campo de instancia.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.Iis processed exactly as ifIwas an instance field. - De lo contrario, el resultado es un evento de acceso con una expresión de instancia asociada de
E.Otherwise, the result is an event access with an associated instance expression ofE.
- Si la referencia se produce dentro de la clase o estructura en la que se declara el evento y el evento se declaró sin event_accessor_declarations (eventos), y la referencia no se produce como el lado izquierdo de un
- En primer lugar, si
- De lo contrario, se intenta procesar
E.Icomo una invocación de método de extensión (invocaciones de método de extensión).Otherwise, an attempt is made to processE.Ias an extension method invocation (Extension method invocations). Si se produce un error,E.Ies una referencia de miembro no válida y se produce un error en tiempo de enlace.If this fails,E.Iis an invalid member reference, and a binding-time error occurs.
Nombres simples y nombres de tipo idénticosIdentical simple names and type names
En un acceso de miembro del formulario E.I , si E es un identificador único, y si el significado de E como simple_name (nombres simples) es una constante, un campo, una propiedad, una variable local o un parámetro con el mismo tipo que el significado de E como type_name (espacio de nombres y nombres de tipo), se permiten ambos significados posibles E .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. Los dos significados posibles de E.I nunca son ambiguos, ya que I debe ser necesariamente miembro del tipo E en ambos 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. En otras palabras, la regla simplemente permite el acceso a los miembros estáticos y los tipos anidados E en los que, de lo contrario, se produciría un error en tiempo de compilación.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 ejemplo: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
}
}
Ambigüedades de la gramáticaGrammar ambiguities
Las producciones de simple_name (nombres simples) y member_access (acceso a miembros) pueden dar lugar a ambigüedades en la gramática de expresiones.The productions for simple_name (Simple names) and member_access (Member access) can give rise to ambiguities in the grammar for expressions. Por ejemplo, la instrucción:For example, the statement:
F(G<A,B>(7));
podría interpretarse como una llamada a F con dos argumentos, G < A y B > (7) .could be interpreted as a call to F with two arguments, G < A and B > (7). Como alternativa, podría interpretarse como una llamada a F con un argumento, que es una llamada a un método genérico G con dos argumentos de tipo y un argumento normal.Alternatively, it could be interpreted as a call to F with one argument, which is a call to a generic method G with two type arguments and one regular argument.
Si se puede analizar una secuencia de tokens (en contexto) como simple_name (nombres simples), member_access (acceso a miembros) o pointer_member_access (acceso a miembros de puntero) que finaliza con un type_argument_list (argumentos de tipo), se examina el token inmediatamente posterior al token de cierre > .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. Si es uno deIf it is one of
( ) ] } : ; , . ? == != | ^
a continuación, el type_argument_list se conserva como parte del simple_name, member_access o pointer_member_access y se descarta cualquier otro posible análisis de la secuencia de tokens.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. De lo contrario, el type_argument_list no se considera parte de la simple_name, member_access o pointer_member_access, aunque no haya ningún otro análisis posible de la secuencia 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. Tenga en cuenta que estas reglas no se aplican al analizar una type_argument_list en un namespace_or_type_name (espacio de nombres y nombres 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). La instrucciónThe statement
F(G<A,B>(7));
, según esta regla, se interpretará como una llamada a F con un argumento, que es una llamada a un método genérico G con dos argumentos de tipo y un argumento normal.will, according to this rule, be interpreted as a call to F with one argument, which is a call to a generic method G with two type arguments and one regular argument. Las instruccionesThe statements
F(G < A, B > 7);
F(G < A, B >> 7);
cada uno de ellos se interpretará como una llamada a F con dos argumentos.will each be interpreted as a call to F with two arguments. La instrucciónThe statement
x = F < A > +y;
se interpretará como un operador menor que, mayor que y unario más, como si se hubiera escrito la instrucción x = (F < A) > (+y) , en lugar de un simple_name con un type_argument_list seguido de un operador binario 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. En la instrucciónIn the statement
x = y is C<T> + z;
los tokens C<T> se interpretan como un namespace_or_type_name con un type_argument_list.the tokens C<T> are interpreted as a namespace_or_type_name with a type_argument_list.
Expresiones de invocaciónInvocation expressions
Un invocation_expression se utiliza para invocar un método.An invocation_expression is used to invoke a method.
invocation_expression
: primary_expression '(' argument_list? ')'
;
Un invocation_expression está enlazado dinámicamente (enlace dinámico) si al menos uno de los siguientes contiene:An invocation_expression is dynamically bound (Dynamic binding) if at least one of the following holds:
- El primary_expression tiene el tipo en tiempo de compilación
dynamic.The primary_expression has compile-time typedynamic. - Al menos un argumento del argument_list opcional tiene el tipo en tiempo de compilación
dynamicy el primary_expression no tiene un tipo de delegado.At least one argument of the optional argument_list has compile-time typedynamicand the primary_expression does not have a delegate type.
En este caso, el compilador clasifica el invocation_expression como un valor de tipo dynamic .In this case the compiler classifies the invocation_expression as a value of type dynamic. A continuación, se aplican las siguientes reglas para determinar el significado de la invocation_expression en tiempo de ejecución, utilizando el tipo en tiempo de ejecución en lugar del tipo en tiempo de compilación de los primary_expression y argumentos que tienen el tipo en tiempo de compilación 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. Si el primary_expression no tiene el tipo en tiempo de compilación dynamic , la invocación del método sufre una comprobación limitada del tiempo de compilación, como se describe en comprobación en tiempo de compilación de la resolución de sobrecarga dinámica.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.
El primary_expression de una invocation_expression debe ser un grupo de métodos o un valor de un delegate_type.The primary_expression of an invocation_expression must be a method group or a value of a delegate_type. Si el primary_expression es un grupo de métodos, el invocation_expression es una invocación de método (invocaciones de método).If the primary_expression is a method group, the invocation_expression is a method invocation (Method invocations). Si el primary_expression es un valor de un delegate_type, el invocation_expression es una invocación de delegado (invocaciones de delegado).If the primary_expression is a value of a delegate_type, the invocation_expression is a delegate invocation (Delegate invocations). Si el primary_expression no es un grupo de métodos ni un valor de un delegate_type, se produce un error en tiempo de enlace.If the primary_expression is neither a method group nor a value of a delegate_type, a binding-time error occurs.
El argument_list opcional (listas de argumentos) proporciona valores o referencias a variables para los parámetros del método.The optional argument_list (Argument lists) provides values or variable references for the parameters of the method.
El resultado de evaluar una invocation_expression se clasifica como sigue:The result of evaluating an invocation_expression is classified as follows:
- Si el invocation_expression invoca un método o un delegado que devuelve
void, el resultado es Nothing.If the invocation_expression invokes a method or delegate that returnsvoid, the result is nothing. Una expresión que se clasifique como Nothing solo se permite en el contexto de una statement_expression (instrucciones de expresión) o como el cuerpo de un lambda_expression (expresiones de función anónima).An expression that is classified as nothing is permitted only in the context of a statement_expression (Expression statements) or as the body of a lambda_expression (Anonymous function expressions). En caso contrario, se produce un error en tiempo de enlace.Otherwise a binding-time error occurs. - De lo contrario, el resultado es un valor del tipo devuelto por el método o el delegado.Otherwise, the result is a value of the type returned by the method or delegate.
Invocaciones de métodoMethod invocations
En el caso de una invocación de método, el primary_expression de la invocation_expression debe ser un grupo de métodos.For a method invocation, the primary_expression of the invocation_expression must be a method group. El grupo de métodos identifica el método que se va a invocar o el conjunto de métodos sobrecargados desde los que se va a elegir un método específico que se va a invocar.The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke. En el último caso, la determinación del método específico que se va a invocar se basa en el contexto proporcionado por los tipos de los argumentos en el 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.
El procesamiento en tiempo de enlace de una invocación de método con el formato M(A) , donde M es un grupo de métodos (posiblemente incluido un type_argument_list) y A es un argument_list opcional, consta de los siguientes pasos: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:
- Se construye el conjunto de métodos candidatos para la invocación del método.The set of candidate methods for the method invocation is constructed. Para cada método
Fasociado al grupo de métodosM:For each methodFassociated with the method groupM:- Si
Fno es genérico,Fes un candidato cuando:IfFis non-generic,Fis a candidate when:Mno tiene ninguna lista de argumentos de tipo yMhas no type argument list, andFes aplicable con respecto aA(miembro de función aplicable).Fis applicable with respect toA(Applicable function member).
- Si
Fes genérico yMno tiene ninguna lista de argumentos de tipo,Fes un candidato cuando:IfFis generic andMhas no type argument list,Fis a candidate when:- La inferencia de tipos (inferencia de tipo) se realiza correctamente, deduciendo una lista de argumentos de tipo para la llamada yType inference (Type inference) succeeds, inferring a list of type arguments for the call, and
- Una vez que los argumentos de tipo deducido se sustituyen por los parámetros de tipo de método correspondientes, todos los tipos construidos en la lista de parámetros de F satisfacen sus restricciones (quecumplencon las restricciones) y la lista de parámetros de
Fes aplicable con respecto aA(miembro defunción aplicable).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 ofFis applicable with respect toA(Applicable function member).
- Si
Fes genérico eMincluye una lista de argumentos de tipo,Fes un candidato cuando:IfFis generic andMincludes a type argument list,Fis a candidate when:Ftiene el mismo número de parámetros de tipo de método que se proporcionaron en la lista de argumentos de tipo yFhas the same number of method type parameters as were supplied in the type argument list, and- Una vez que los argumentos de tipo se sustituyen por los parámetros de tipo de método correspondientes, todos los tipos construidos en la lista de parámetros de F satisfacen sus restricciones (quecumplencon las restricciones) y la lista de parámetros de
Fes aplicable con respecto aA(miembro defunción aplicable).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 ofFis applicable with respect toA(Applicable function member).
- Si
- El conjunto de métodos candidatos se reduce para que solo contengan métodos de los tipos más derivados: para cada método del
C.Fconjunto, dondeCes el tipo en el queFse declara el método, todos los métodos declarados en un tipo base deCse quitan del conjunto.The set of candidate methods is reduced to contain only methods from the most derived types: For each methodC.Fin the set, whereCis the type in which the methodFis declared, all methods declared in a base type ofCare removed from the set. Además, siCes un tipo de clase distinto deobject, todos los métodos declarados en un tipo de interfaz se quitan del conjunto.Furthermore, ifCis a class type other thanobject, all methods declared in an interface type are removed from the set. (Esta última regla solo tiene efecto cuando el grupo de métodos era el resultado de una búsqueda de miembros en un parámetro de tipo que tiene una clase base efectiva que no es un objeto y un conjunto de interfaces efectivo no vacío).(This latter rule only has affect when the method group was the result of a member lookup on a type parameter having an effective base class other than object and a non-empty effective interface set.) - Si el conjunto resultante de métodos candidatos está vacío, se abandona el procesamiento posterior a lo largo de los pasos siguientes y, en su lugar, se intenta procesar la invocación como una invocación de método de extensión (invocaciones de método de extensión).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). Si se produce un error, no existe ningún método aplicable y se produce un error en tiempo de enlace.If this fails, then no applicable methods exist, and a binding-time error occurs.
- El mejor método del conjunto de métodos candidatos se identifica mediante las reglas de resolución de sobrecarga de la resolución de sobrecarga.The best method of the set of candidate methods is identified using the overload resolution rules of Overload resolution. Si no se puede identificar un único método mejor, la invocación del método es ambigua y se produce un error en tiempo de enlace.If a single best method cannot be identified, the method invocation is ambiguous, and a binding-time error occurs. Al realizar la resolución de sobrecarga, los parámetros de un método genérico se tienen en cuenta después de sustituir los argumentos de tipo (proporcionados o deducidos) para los parámetros de tipo de método correspondientes.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.
- Se realiza la validación final del mejor método elegido:Final validation of the chosen best method is performed:
- El método se valida en el contexto del grupo de métodos: Si el mejor método es un método estático, el grupo de métodos debe haber sido el resultado de un simple_name o de un member_access a través de un 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. Si el mejor método es un método de instancia, el grupo de métodos debe haber sido el resultado de un simple_name, un member_access a través de una variable o un valor, o un base_access.If the best method is an instance method, the method group must have resulted from a simple_name, a member_access through a variable or value, or a base_access. Si ninguno de estos requisitos es true, se produce un error en tiempo de enlace.If neither of these requirements is true, a binding-time error occurs.
- Si el mejor método es un método genérico, los argumentos de tipo (suministrados o deducidos) se comprueban con las restricciones (quecumplen las restricciones) declaradas en el 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. Si algún argumento de tipo no satisface las restricciones correspondientes en el parámetro de tipo, se produce un error en tiempo de enlace.If any type argument does not satisfy the corresponding constraint(s) on the type parameter, a binding-time error occurs.
Una vez que se ha seleccionado y validado un método en tiempo de enlace según los pasos anteriores, la invocación real en tiempo de ejecución se procesa de acuerdo con las reglas de invocación de miembros de función descritas en la comprobación en tiempo de compilación de la resolución 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.
El efecto intuitivo de las reglas de resolución descritas anteriormente es el siguiente: para encontrar el método determinado invocado por una invocación de método, empiece con el tipo indicado por la invocación del método y continúe con la cadena de herencia hasta que se encuentre al menos una declaración de método aplicable, accesible y que no sea de invalidación.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. A continuación, realice la inferencia de tipos y la resolución de sobrecarga en el conjunto de métodos aplicables, accesibles y no invalidaciones declarados en ese tipo e invoque el método de la forma que se seleccione.Then perform type inference and overload resolution on the set of applicable, accessible, non-override methods declared in that type and invoke the method thus selected. Si no se encuentra ningún método, pruebe en su lugar para procesar la invocación como una invocación de método de extensión.If no method was found, try instead to process the invocation as an extension method invocation.
Invocaciones de métodos de extensiónExtension method invocations
En una invocación de método (invocaciones en instancias de conversión boxing) de uno de los formulariosIn a method invocation (Invocations on boxed instances) of one of the forms
expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )
Si el procesamiento normal de la invocación no encuentra ningún método aplicable, se realiza un intento de procesar la construcción como una invocación de método de extensión.if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. Si expr o cualquiera de los argumentos tiene el tipo en tiempo de compilación dynamic , los métodos de extensión no se aplicarán.If expr or any of the args has compile-time type dynamic, extension methods will not apply.
El objetivo es encontrar el mejor type_name C , de modo que pueda tener lugar la invocación de método estático correspondiente: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 )
Un método de extensión Ci.Mj es válido si:An extension method Ci.Mj is eligible if:
Cies una clase no genérica y no anidadaCiis a non-generic, non-nested class- El nombre de
Mjes IdentifierThe name ofMjis identifier Mjes accesible y aplicable cuando se aplica a los argumentos como un método estático, como se muestra arriba.Mjis accessible and applicable when applied to the arguments as a static method as shown above- Existe una conversión implícita de identidad, de referencia o de conversión boxing de expr al tipo del primer parámetro de
Mj.An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter ofMj.
La búsqueda de C continúa como sigue:The search for C proceeds as follows:
- A partir de la declaración de espacio de nombres envolvente más cercana, continuando con cada declaración de espacio de nombres envolvente y finalizando con la unidad de compilación que lo contiene, se realizan sucesivos intentos para buscar un conjunto candidato de métodos de extensión:Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods:
- Si el espacio de nombres o la unidad de compilación especificados contiene directamente declaraciones de tipos no genéricos
Cicon métodos de extensión válidosMj, el conjunto de estos métodos de extensión es el conjunto de candidatos.If the given namespace or compilation unit directly contains non-generic type declarationsCiwith eligible extension methodsMj, then the set of those extension methods is the candidate set. - Si los tipos
Ciimportados por using_static_declarations y que se declaran directamente en los espacios de nombres importados por using_namespace_directive s en el espacio de nombres o la unidad de compilación especificados directamente contienen métodos de extensión válidosMj, el conjunto de estos métodos de extensión es el conjunto de candidatos.If typesCiimported 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.
- Si el espacio de nombres o la unidad de compilación especificados contiene directamente declaraciones de tipos no genéricos
- Si no se encuentra ningún conjunto candidato en ninguna declaración de espacio de nombres envolvente o unidad de compilación, se produce un error en tiempo de compilación.If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
- De lo contrario, se aplica la resolución de sobrecarga al conjunto de candidatos tal y como se describe en (resolución de sobrecarga).Otherwise, overload resolution is applied to the candidate set as described in (Overload resolution). Si no se encuentra ningún método mejor, se produce un error en tiempo de compilación.If no single best method is found, a compile-time error occurs.
Ces el tipo en el que se declara el mejor método como método de extensión.Cis the type within which the best method is declared as an extension method.
Con C como destino, la llamada al método se procesa a continuación como una invocación de método estático (comprobación en tiempo de compilación de la resolución 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).
Las reglas anteriores implican que los métodos de instancia tienen prioridad sobre los métodos de extensión, que los métodos de extensión disponibles en las declaraciones de espacios de nombres internos tienen prioridad sobre los métodos de extensión disponibles en las declaraciones de espacios de nombres exteriores y que los métodos de extensión declarados directamente en un espacio de nombres tienen prioridad sobre los métodos de extensión importados en el mismo espacio de nombres con una directivaThe 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 ejemplo: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)
}
}
En el ejemplo, el B método de tiene prioridad sobre el primer método de extensión y el C método de tiene prioridad sobre ambos métodos de extensión.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();
}
}
}
El resultado de este ejemplo es:The output of this example is:
E.F(1)
D.G(2)
C.H(3)
D.G tiene prioridad sobre y C.G E.F tiene prioridad sobre D.F y C.F .D.G takes precedence over C.G, and E.F takes precedence over both D.F and C.F.
Invocaciones de delegadoDelegate invocations
En el caso de una invocación de delegado, el primary_expression de la invocation_expression debe ser un valor de un delegate_type.For a delegate invocation, the primary_expression of the invocation_expression must be a value of a delegate_type. Además, si se considera que el delegate_type ser un miembro de función con la misma lista de parámetros que el delegate_type, el delegate_type debe ser aplicable (miembro de función aplicable) con respecto al argument_list del 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.
El procesamiento en tiempo de ejecución de una invocación de delegado con el formato D(A) , donde D es una primary_expression de un delegate_type y A es un argument_list opcional, consta de los siguientes pasos: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:
Dse evalúa.Dis evaluated. Si esta evaluación provoca una excepción, no se ejecuta ningún paso más.If this evaluation causes an exception, no further steps are executed.DSe comprueba que el valor de es válido.The value ofDis checked to be valid. Si el valor deDesnull,System.NullReferenceExceptionse produce una excepción y no se ejecuta ningún paso más.If the value ofDisnull, aSystem.NullReferenceExceptionis thrown and no further steps are executed.- De lo contrario,
Des una referencia a una instancia de delegado.Otherwise,Dis a reference to a delegate instance. Las invocaciones de miembros de función (comprobación en tiempo de compilación de la resolución dinámica de sobrecarga) se realizan en cada una de las entidades a las que se puede llamar en la lista de invocaciones del 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 las entidades a las que se puede llamar que se componen de un método de instancia y de instancia, la instancia de para la invocación es la instancia contenida en la entidad a la que se puedeFor callable entities consisting of an instance and instance method, the instance for the invocation is the instance contained in the callable entity.
Acceso a elementosElement access
Un element_access consta de un primary_no_array_creation_expression, seguido de un [ token "", seguido de un argument_list, seguido de un ] 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. El argument_list se compone de uno o más argumentos, separados por comas.The argument_list consists of one or more argument s, separated by commas.
element_access
: primary_no_array_creation_expression '[' expression_list ']'
;
La argument_list de un element_access no puede contener ref out argumentos o.The argument_list of an element_access is not allowed to contain ref or out arguments.
Un element_access está enlazado dinámicamente (enlace dinámico) si al menos uno de los siguientes contiene:An element_access is dynamically bound (Dynamic binding) if at least one of the following holds:
- El primary_no_array_creation_expression tiene el tipo en tiempo de compilación
dynamic.The primary_no_array_creation_expression has compile-time typedynamic. - Al menos una expresión de la argument_list tiene el tipo en tiempo de compilación
dynamicy el primary_no_array_creation_expression no tiene un tipo de matriz.At least one expression of the argument_list has compile-time typedynamicand the primary_no_array_creation_expression does not have an array type.
En este caso, el compilador clasifica el element_access como un valor de tipo dynamic .In this case the compiler classifies the element_access as a value of type dynamic. A continuación, se aplican las siguientes reglas para determinar el significado de la element_access en tiempo de ejecución, utilizando el tipo en tiempo de ejecución en lugar del tipo en tiempo de compilación de las expresiones primary_no_array_creation_expression y argument_list que tienen el tipo en tiempo de compilación dynamic .The rules below to determine the meaning of the element_access are then applied at run-time, using the run-time type instead of the compile-time type of those of the primary_no_array_creation_expression and argument_list expressions which have the compile-time type dynamic. Si el primary_no_array_creation_expression no tiene el tipo en tiempo de compilación dynamic , el acceso al elemento sufre una comprobación de tiempo de compilación limitada, como se describe en comprobación en tiempo de compilación de la resolución de sobrecarga dinámica.If the primary_no_array_creation_expression does not have compile-time type dynamic, then the element access undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.
Si el primary_no_array_creation_expression de una element_access es un valor de un array_type, el element_access es un acceso a la matriz (acceso a la 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). De lo contrario, el primary_no_array_creation_expression debe ser una variable o un valor de una clase, estructura o tipo de interfaz que tenga uno o más miembros del indexador, en cuyo caso el element_access es un acceso de indexador (acceso del 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).
Acceso a matrizArray access
Para un acceso de matriz, el primary_no_array_creation_expression de la element_access debe ser un valor de un array_type.For an array access, the primary_no_array_creation_expression of the element_access must be a value of an array_type. Además, el argument_list de un acceso de matriz no puede contener argumentos con nombre. El número de expresiones en el argument_list debe ser el mismo que el rango de la array_type, y cada expresión debe ser de tipo int , uint , long , ulong o debe poder convertirse implícitamente a uno o varios de estos 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.
El resultado de evaluar un acceso de matriz es una variable del tipo de elemento de la matriz, es decir, el elemento de matriz seleccionado por los valores de las expresiones de la 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.
El procesamiento en tiempo de ejecución de un acceso de matriz del formulario P[A] , donde P es una primary_no_array_creation_expression de un array_type y A es un argument_list, consta de los siguientes pasos: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:
Pse evalúa.Pis evaluated. Si esta evaluación provoca una excepción, no se ejecuta ningún paso más.If this evaluation causes an exception, no further steps are executed.- Las expresiones de índice del argument_list se evalúan en orden, de izquierda a derecha.The index expressions of the argument_list are evaluated in order, from left to right. Después de la evaluación de cada expresión de índice, se realiza una conversión implícita (conversiones implícitas) en uno de los siguientes tipos:
int,uint,long,ulong.Following evaluation of each index expression, an implicit conversion (Implicit conversions) to one of the following types is performed:int,uint,long,ulong. Se elige el primer tipo de esta lista para el que existe una conversión implícita.The first type in this list for which an implicit conversion exists is chosen. Por ejemplo, si la expresión de índice es de tiposhort, se realiza una conversión implícita aint, ya que es posible realizar conversiones implícitas deshortainty deshortalong.For instance, if the index expression is of typeshortthen an implicit conversion tointis performed, since implicit conversions fromshorttointand fromshorttolongare possible. Si la evaluación de una expresión de índice o de la conversión implícita subsiguiente produce una excepción, no se evalúan más expresiones de índice y no se ejecuta ningún paso más.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. PSe comprueba que el valor de es válido.The value ofPis checked to be valid. Si el valor dePesnull,System.NullReferenceExceptionse produce una excepción y no se ejecuta ningún paso más.If the value ofPisnull, aSystem.NullReferenceExceptionis thrown and no further steps are executed.- El valor de cada expresión del argument_list se comprueba con respecto a los límites reales de cada dimensión de la instancia de la matriz a la que hace referencia
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. Si uno o más valores están fuera del intervalo,System.IndexOutOfRangeExceptionse produce una excepción y no se ejecuta ningún paso más.If one or more values are out of range, aSystem.IndexOutOfRangeExceptionis thrown and no further steps are executed. - Se calcula la ubicación del elemento de matriz proporcionado por las expresiones de índice y esta ubicación se convierte en el resultado del acceso a la 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.
Acceso a indizadorIndexer access
En el caso de un acceso de indexador, el primary_no_array_creation_expression de la element_access debe ser una variable o valor de un tipo de clase, struct o interfaz, y este tipo debe implementar uno o más indexadores aplicables con respecto a la argument_list del 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.
El procesamiento en tiempo de enlace de un acceso del indizador del formulario P[A] , donde P es una primary_no_array_creation_expression de una clase, un struct o un tipo de interfaz T , y A es un argument_list, consta de los siguientes pasos: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:
- Se crea el conjunto de indexadores proporcionado por
T.The set of indexers provided byTis constructed. El conjunto está formado por todos los indizadores declarados enTo un tipo base deTque no sonoverridedeclaraciones y son accesibles en el contexto actual (acceso a miembros).The set consists of all indexers declared inTor a base type ofTthat are notoverridedeclarations and are accessible in the current context (Member access). - El conjunto se reduce a los indizadores aplicables y no ocultos por otros indexadores.The set is reduced to those indexers that are applicable and not hidden by other indexers. Las siguientes reglas se aplican a cada indexador del
S.Iconjunto, dondeSes el tipo en el que se declara el indexadorI:The following rules are applied to each indexerS.Iin the set, whereSis the type in which the indexerIis declared:- Si
Ino es aplicable con respecto aA(miembro de función aplicable),Ise quita del conjunto.IfIis not applicable with respect toA(Applicable function member), thenIis removed from the set. - Si
Ies aplicable con respecto aA(miembro de función aplicable), todos los indexadores declarados en un tipo base deSse quitan del conjunto.IfIis applicable with respect toA(Applicable function member), then all indexers declared in a base type ofSare removed from the set. - Si
Ies aplicable con respecto aA(miembro de función aplicable) ySes un tipo de clase distinto deobject, todos los indexadores declarados en una interfaz se quitan del conjunto.IfIis applicable with respect toA(Applicable function member) andSis a class type other thanobject, all indexers declared in an interface are removed from the set.
- Si
- Si el conjunto resultante de indizadores candidatos está vacío, no existe ningún indexador aplicable y se produce un error en tiempo de enlace.If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
- El mejor indexador del conjunto de indizadores candidatos se identifica mediante las reglas de resolución de sobrecarga de la resolución de sobrecarga.The best indexer of the set of candidate indexers is identified using the overload resolution rules of Overload resolution. Si no se puede identificar un único indexador mejor, el acceso del indexador es ambiguo y se produce un error en tiempo de enlace.If a single best indexer cannot be identified, the indexer access is ambiguous, and a binding-time error occurs.
- Las expresiones de índice del argument_list se evalúan en orden, de izquierda a derecha.The index expressions of the argument_list are evaluated in order, from left to right. El resultado de procesar el acceso del indexador es una expresión clasificada como un acceso de indexador.The result of processing the indexer access is an expression classified as an indexer access. La expresión de acceso del indizador hace referencia al indizador determinado en el paso anterior y tiene una expresión de instancia asociada de
Py una lista de argumentos asociada deA.The indexer access expression references the indexer determined in the step above, and has an associated instance expression ofPand an associated argument list ofA.
En función del contexto en el que se utiliza, un acceso de indexador provoca la invocación del descriptor de acceso get o del descriptor de acceso set del 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. Si el acceso del indizador es el destino de una asignación, se invoca al descriptor de acceso set para asignar un nuevo valor (asignación simple).If the indexer access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). En todos los demás casos, el descriptor de acceso get se invoca para obtener el valor actual (valores de las expresiones).In all other cases, the get accessor is invoked to obtain the current value (Values of expressions).
Este accesoThis access
Un this_access consta de la palabra reservada this .A this_access consists of the reserved word this.
this_access
: 'this'
;
Solo se permite un this_access en el bloque de un constructor de instancia, un método de instancia o un descriptor de acceso de instancia.A this_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Tiene uno de los significados siguientes:It has one of the following meanings:
- Cuando
thisse utiliza en una primary_expression dentro de un constructor de instancia de una clase, se clasifica como un valor.Whenthisis used in a primary_expression within an instance constructor of a class, it is classified as a value. El tipo del valor es el tipo de instancia (el tipo de instancia) de la clase en la que se produce el uso y el valor es una referencia al objeto que se está construyendo.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. - Cuando
thisse utiliza en una primary_expression dentro de un método de instancia o un descriptor de acceso de instancia de una clase, se clasifica como un valor.Whenthisis used in a primary_expression within an instance method or instance accessor of a class, it is classified as a value. El tipo del valor es el tipo de instancia (el tipo de instancia) de la clase en la que se produce el uso y el valor es una referencia al objeto para el que se invocó el método o el descriptor de acceso.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. - Cuando
thisse utiliza en una primary_expression dentro de un constructor de instancia de un struct, se clasifica como una variable.Whenthisis used in a primary_expression within an instance constructor of a struct, it is classified as a variable. El tipo de la variable es el tipo de instancia (el tipo de instancia) del struct en el que se produce el uso y la variable representa el struct que se está construyendo.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. Lathisvariable de un constructor de instancia de una estructura se comporta exactamente igual que unoutparámetro del tipo de estructura; en concreto, esto significa que la variable debe estar asignada definitivamente en todas las rutas de acceso de ejecución del constructor de instancia.Thethisvariable of an instance constructor of a struct behaves exactly the same as anoutparameter of the struct type—in particular, this means that the variable must be definitely assigned in every execution path of the instance constructor. - Cuando
thisse utiliza en una primary_expression dentro de un método de instancia o un descriptor de acceso de instancia de un struct, se clasifica como una variable.Whenthisis used in a primary_expression within an instance method or instance accessor of a struct, it is classified as a variable. El tipo de la variable es el tipo de instancia (el tipo de instancia) del struct en el que se produce el uso.The type of the variable is the instance type (The instance type) of the struct within which the usage occurs.- Si el método o el descriptor de acceso no es un iterador (iteradores), la
thisvariable representa la estructura para la que se invocó el método o descriptor de acceso, y se comporta exactamente igual que unrefparámetro del tipo de estructura.If the method or accessor is not an iterator (Iterators), thethisvariable represents the struct for which the method or accessor was invoked, and behaves exactly the same as arefparameter of the struct type. - Si el método o descriptor de acceso es un iterador, la
thisvariable representa una copia del struct para el que se invocó el método o descriptor de acceso, y se comporta exactamente igual que un parámetro de valor del tipo de estructura.If the method or accessor is an iterator, thethisvariable 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.
- Si el método o el descriptor de acceso no es un iterador (iteradores), la
El uso de this en una primary_expression en un contexto distinto de los enumerados anteriormente es un error en tiempo de compilación.Use of this in a primary_expression in a context other than the ones listed above is a compile-time error. En concreto, no es posible hacer referencia a this en un método estático, un descriptor de acceso de propiedad estática o en una variable_initializer de una declaración 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.
Acceso baseBase access
Un base_access consta de la palabra reservada base seguida de un . token "" y un identificador o un argument_list entre corchetes:A base_access consists of the reserved word base followed by either a "." token and an identifier or an argument_list enclosed in square brackets:
base_access
: 'base' '.' identifier
| 'base' '[' expression_list ']'
;
Un base_access se utiliza para tener acceso a los miembros de clase base que están ocultos por miembros con el mismo nombre en la clase o el struct actual.A base_access is used to access base class members that are hidden by similarly named members in the current class or struct. Solo se permite un base_access en el bloque de un constructor de instancia, un método de instancia o un descriptor de acceso de instancia.A base_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Cuando base.I se produce en una clase o struct, I debe indicar un miembro de la clase base de esa clase o estructura.When base.I occurs in a class or struct, I must denote a member of the base class of that class or struct. Del mismo modo, cuando base[E] se produce en una clase, debe existir un indexador aplicable en la clase base.Likewise, when base[E] occurs in a class, an applicable indexer must exist in the base class.
En tiempo de enlace, base_access expresiones del formulario base.I y base[E] se evalúan exactamente como si se hubieran escrito ((B)this).I y ((B)this)[E] , donde B es la clase base de la clase o estructura en la que se produce la construcción.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. Así, base.I y base[E] corresponden a this.I y this[E] , salvo this que se ve como una instancia de la clase 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.
Cuando un base_access hace referencia a un miembro de función virtual (un método, una propiedad o un indizador), se cambia la determinación del miembro de función que se va a invocar en tiempo de ejecución (comprobación en tiempo de compilación de la resolución dinámica de sobrecarga).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. El miembro de función que se invoca se determina mediante la búsqueda de la implementación más derivada (métodos virtuales) del miembro de función con respecto a B (en lugar de con respecto al tipo en tiempo de ejecución de this , como sería habitual en un acceso no 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). Por lo tanto, dentro override de un virtual miembro de función, se puede usar un base_access para invocar la implementación heredada del miembro de función.Thus, within an override of a virtual function member, a base_access can be used to invoke the inherited implementation of the function member. Si el miembro de función al que hace referencia una base_access es abstracto, se produce un error en tiempo de enlace.If the function member referenced by a base_access is abstract, a binding-time error occurs.
Operadores de incremento y decremento posfijosPostfix increment and decrement operators
post_increment_expression
: primary_expression '++'
;
post_decrement_expression
: primary_expression '--'
;
El operando de una operación de incremento o decremento postfijo debe ser una expresión clasificada como una variable, un acceso de propiedad o un acceso 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. El resultado de la operación es un valor del mismo tipo que el operando.The result of the operation is a value of the same type as the operand.
Si el primary_expression tiene el tipo en tiempo de compilación dynamic , el operador está enlazado dinámicamente (enlace dinámico), el post_increment_expression o post_decrement_expression tiene el tipo en tiempo de compilación dynamic y se aplican las siguientes reglas en tiempo de ejecución utilizando el tipo en tiempo de ejecución del primary_expression.If the primary_expression has the compile-time type dynamic then the operator is dynamically bound (Dynamic binding), the post_increment_expression or post_decrement_expression has the compile-time type dynamic and the following rules are applied at run-time using the run-time type of the primary_expression.
Si el operando de una operación de incremento o decremento postfijo es una propiedad o un indexador, la propiedad o el indexador deben tener un get set descriptor de acceso y.If the operand of a postfix increment or decrement operation is a property or indexer access, the property or indexer must have both a get and a set accessor. Si no es así, se produce un error en tiempo de enlace.If this is not the case, a binding-time error occurs.
La resolución de sobrecargas de operador unario (resolución de sobrecarga de operadores unarios) se aplica para seleccionar una implementación de operador específica.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. ++Existen operadores y predefinidos -- para los tipos siguientes: sbyte , byte , short , ushort , int , uint ,,, long ulong char , float , double , decimal y cualquier tipo de enumeración.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Los operadores predefinidos ++ devuelven el valor generado agregando 1 al operando y los operadores predefinidos -- devuelven el valor generado restando 1 del 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. En un checked contexto, si el resultado de esta suma o resta está fuera del intervalo del tipo de resultado y el tipo de resultado es un tipo entero o de enumeración, System.OverflowException se produce una excepción.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.
El procesamiento en tiempo de ejecución de una operación de incremento o decremento postfijo del formulario x++ o x-- consta de los siguientes pasos:The run-time processing of a postfix increment or decrement operation of the form x++ or x-- consists of the following steps:
- Si
xse clasifica como una variable:Ifxis classified as a variable:xse evalúa para generar la variable.xis evaluated to produce the variable.- El valor de
xse guarda.The value ofxis saved. - El operador seleccionado se invoca con el valor guardado de
xcomo argumento.The selected operator is invoked with the saved value ofxas its argument. - El valor devuelto por el operador se almacena en la ubicación especificada por la evaluación de
x.The value returned by the operator is stored in the location given by the evaluation ofx. - El valor guardado de
xse convierte en el resultado de la operación.The saved value ofxbecomes the result of the operation.
- Si
xse clasifica como un acceso de propiedad o indizador:Ifxis classified as a property or indexer access:- La expresión de instancia (si
xno esstatic) y la lista de argumentos (sixes un acceso de indexador) asociadas axse evalúan, y los resultados se usan en lasgetsetllamadas a descriptores de acceso y posteriores.The instance expression (ifxis notstatic) and the argument list (ifxis an indexer access) associated withxare evaluated, and the results are used in the subsequentgetandsetaccessor invocations. getSe invoca el descriptor de acceso dexy se guarda el valor devuelto.Thegetaccessor ofxis invoked and the returned value is saved.- El operador seleccionado se invoca con el valor guardado de
xcomo argumento.The selected operator is invoked with the saved value ofxas its argument. - El
setdescriptor de acceso dexse invoca con el valor devuelto por el operador como suvalueargumento.Thesetaccessor ofxis invoked with the value returned by the operator as itsvalueargument. - El valor guardado de
xse convierte en el resultado de la operación.The saved value ofxbecomes the result of the operation.
- La expresión de instancia (si
Los ++ -- operadores y también admiten la notación de prefijo (operadores de incremento y decremento de prefijo).The ++ and -- operators also support prefix notation (Prefix increment and decrement operators). Normalmente, el resultado de x++ o x-- es el valor de x antes de la operación, mientras que el resultado de ++x o --x es el valor de x después de la operación.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. En cualquier caso, x tiene el mismo valor después de la operación.In either case, x itself has the same value after the operation.
Una operator ++ implementación de o operator -- se puede invocar mediante la notación de prefijo o postfijo.An operator ++ or operator -- implementation can be invoked using either postfix or prefix notation. No es posible tener implementaciones de operador independientes para las dos notaciones.It is not possible to have separate operator implementations for the two notations.
Operador newThe new operator
El new operador se usa para crear nuevas instancias de tipos.The new operator is used to create new instances of types.
Hay tres formas de new expresiones:There are three forms of new expressions:
- Las expresiones de creación de objetos se utilizan para crear nuevas instancias de tipos de clase y tipos de valor.Object creation expressions are used to create new instances of class types and value types.
- Las expresiones de creación de matrices se utilizan para crear nuevas instancias de tipos de matriz.Array creation expressions are used to create new instances of array types.
- Las expresiones de creación de delegados se utilizan para crear nuevas instancias de tipos de delegado.Delegate creation expressions are used to create new instances of delegate types.
El new operador implica la creación de una instancia de un tipo, pero no implica necesariamente la asignación dinámica de memoria.The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. En concreto, las instancias de tipos de valor no requieren memoria adicional más allá de las variables en las que residen, y no se produce ninguna asignación dinámica cuando new se usa para crear instancias 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.
Expresiones de creación de objetosObject creation expressions
Un object_creation_expression se usa para crear una nueva instancia de un class_type o un value_type.An object_creation_expression is used to create a new instance of a class_type or a value_type.
object_creation_expression
: 'new' type '(' argument_list? ')' object_or_collection_initializer?
| 'new' type object_or_collection_initializer
;
object_or_collection_initializer
: object_initializer
| collection_initializer
;
El tipo de un object_creation_expression debe ser un class_type, un value_type o un type_parameter.The type of an object_creation_expression must be a class_type, a value_type or a type_parameter. El tipo no puede ser un abstract class_type.The type cannot be an abstract class_type.
Solo se permite el argument_list opcional (listas de argumentos) si el tipo es un class_type o un struct_type.The optional argument_list (Argument lists) is permitted only if the type is a class_type or a struct_type.
Una expresión de creación de objeto puede omitir la lista de argumentos del constructor y los paréntesis de cierre especificados que incluye un inicializador de objeto o un inicializador de colección.An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. Omitir la lista de argumentos del constructor y los paréntesis de inclusión equivale a especificar una lista de argumentos vacía.Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.
El procesamiento de una expresión de creación de objetos que incluye un inicializador de objeto o un inicializador de colección consiste en procesar primero el constructor de instancia y después procesar las inicializaciones de miembro o elemento especificadas por el inicializador de objeto (inicializadores de objeto) o el inicializador de colección (inicializadores de colección).Processing of an object creation expression that includes an object initializer or collection initializer consists of first processing the instance constructor and then processing the member or element initializations specified by the object initializer (Object initializers) or collection initializer (Collection initializers).
Si alguno de los argumentos del argument_list opcional tiene el tipo en tiempo de compilación dynamic , el object_creation_expression está enlazado dinámicamente (enlace dinámico) y se aplican las siguientes reglas en tiempo de ejecución utilizando el tipo en tiempo de ejecución de los argumentos de la argument_list que tienen el tipo de tiempo de compilación 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. Sin embargo, la creación de objetos sufre una comprobación de tiempo de compilación limitada, como se describe en comprobación en tiempo de compilación de la resolución dinámica de sobrecarga.However, the object creation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.
El procesamiento en tiempo de enlace de un object_creation_expression del formulario new T(A) , donde T es un class_type o un value_type y A es un argument_list opcional, consta de los siguientes pasos:The binding-time processing of an object_creation_expression of the form new T(A), where T is a class_type or a value_type and A is an optional argument_list, consists of the following steps:
- Si
Tes un value_type yAno está presente:IfTis a value_type andAis not present:- El object_creation_expression es una invocación de constructor predeterminada.The object_creation_expression is a default constructor invocation. El resultado de la object_creation_expression es un valor de tipo
T, es decir, el valor predeterminado paraTtal y como se define en el tipo System. ValueType.The result of the object_creation_expression is a value of typeT, namely the default value forTas defined in The System.ValueType type.
- El object_creation_expression es una invocación de constructor predeterminada.The object_creation_expression is a default constructor invocation. El resultado de la object_creation_expression es un valor de tipo
- De lo contrario, si
Tes un type_parameter yAno está presente:Otherwise, ifTis a type_parameter andAis not present:- Si no se ha especificado ninguna restricción de tipo de valor o restricción de constructor (restricciones de parámetro de tipo) para
T, se produce un error en tiempo de enlace.If no value type constraint or constructor constraint (Type parameter constraints) has been specified forT, a binding-time error occurs. - El resultado de la object_creation_expression es un valor del tipo en tiempo de ejecución al que se ha enlazado el parámetro de tipo, es decir, el resultado de invocar el constructor predeterminado de ese 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. El tipo en tiempo de ejecución puede ser un tipo de referencia o un tipo de valor.The run-time type may be a reference type or a value type.
- Si no se ha especificado ninguna restricción de tipo de valor o restricción de constructor (restricciones de parámetro de tipo) para
- De lo contrario, si
Tes un class_type o un struct_type:Otherwise, ifTis a class_type or a struct_type:- Si
Tes unabstractclass_type, se produce un error en tiempo de compilación.IfTis anabstractclass_type, a compile-time error occurs. - El constructor de instancia que se va a invocar se determina mediante las reglas de resolución de sobrecarga de la resolución de sobrecarga.The instance constructor to invoke is determined using the overload resolution rules of Overload resolution. El conjunto de constructores de instancias candidatas se compone de todos los constructores de instancia accesibles declarados en
Tque se aplican con respecto aA(miembro de función aplicable).The set of candidate instance constructors consists of all accessible instance constructors declared inTwhich are applicable with respect toA(Applicable function member). Si el conjunto de constructores de instancia candidata está vacío, o si no se puede identificar un único constructor de instancia mejor, se produce un error en tiempo de enlace.If the set of candidate instance constructors is empty, or if a single best instance constructor cannot be identified, a binding-time error occurs. - El resultado de la object_creation_expression es un valor de tipo
T, es decir, el valor generado al invocar el constructor de instancia determinado en el paso anterior.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.
- Si
- De lo contrario, el object_creation_expression no es válido y se produce un error en tiempo de enlace.Otherwise, the object_creation_expression is invalid, and a binding-time error occurs.
Aunque el object_creation_expression esté enlazado dinámicamente, el tipo en tiempo de compilación sigue siendo T .Even if the object_creation_expression is dynamically bound, the compile-time type is still T.
El procesamiento en tiempo de ejecución de un object_creation_expression del formulario new T(A) , donde T es class_type o un struct_type y A es un argument_list opcional, consta de los siguientes pasos:The run-time processing of an object_creation_expression of the form new T(A), where T is class_type or a struct_type and A is an optional argument_list, consists of the following steps:
- Si
Tes un class_type:IfTis a class_type:- Se asigna una nueva instancia de la clase
T.A new instance of classTis allocated. Si no hay suficiente memoria disponible para asignar la nueva instancia,System.OutOfMemoryExceptionse produce una excepción y no se ejecuta ningún paso más.If there is not enough memory available to allocate the new instance, aSystem.OutOfMemoryExceptionis thrown and no further steps are executed. - Todos los campos de la nueva instancia se inicializan con sus valores predeterminados (valores predeterminados).All fields of the new instance are initialized to their default values (Default values).
- El constructor de instancia se invoca de acuerdo con las reglas de invocación de miembros de función (comprobación en tiempo de compilación de la resolución dinámica de sobrecarga).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Se pasa automáticamente una referencia a la instancia recién asignada al constructor de instancia y se puede tener acceso a la instancia desde dentro de ese constructor 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.
- Se asigna una nueva instancia de la clase
- Si
Tes un struct_type:IfTis a struct_type:- Una instancia de tipo
Tse crea asignando una variable local temporal.An instance of typeTis created by allocating a temporary local variable. Puesto que se requiere un constructor de instancia de un struct_type para asignar definitivamente un valor a cada campo de la instancia que se va a crear, no es necesario inicializar la variable temporal.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. - El constructor de instancia se invoca de acuerdo con las reglas de invocación de miembros de función (comprobación en tiempo de compilación de la resolución dinámica de sobrecarga).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Se pasa automáticamente una referencia a la instancia recién asignada al constructor de instancia y se puede tener acceso a la instancia desde dentro de ese constructor 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.
- Una instancia de tipo
Inicializadores de objetoObject initializers
Un inicializador de objeto especifica valores para cero o más campos, propiedades o elementos indizados de un 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
;
Un inicializador de objeto consta de una secuencia de inicializadores de miembro, delimitada por { } tokens y y separados por comas.An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas. Cada member_initializer designa un destino para la inicialización.Each member_initializer designates a target for the initialization. Un identificador debe asignar un nombre a un campo o propiedad accesible del objeto que se va a inicializar, mientras que una argument_list entre corchetes debe especificar los argumentos de un indizador accesible en el objeto que se va a inicializar.An identifier must name an accessible field or property of the object being initialized, whereas an argument_list enclosed in square brackets must specify arguments for an accessible indexer on the object being initialized. Es un error que un inicializador de objeto incluya más de un inicializador de miembro para el mismo campo o propiedad.It is an error for an object initializer to include more than one member initializer for the same field or property.
Cada initializer_target va seguido de un signo igual y una expresión, un inicializador de objeto o un inicializador de colección.Each initializer_target is followed by an equals sign and either an expression, an object initializer or a collection initializer. No es posible que las expresiones del inicializador de objeto hagan referencia al objeto recién creado que se está inicializando.It is not possible for expressions within the object initializer to refer to the newly created object it is initializing.
Inicializador de miembro que especifica una expresión después de que el signo igual se procese de la misma manera que una asignación (asignación simple) al 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.
Inicializador de miembro que especifica un inicializador de objeto después de que el signo igual sea un inicializador de objeto anidado, es decir, una inicialización de un objeto incrustado.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. En lugar de asignar un nuevo valor al campo o propiedad, las asignaciones en el inicializador de objeto anidado se tratan como asignaciones a los miembros del campo o de la propiedad.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. Los inicializadores de objeto anidados no se pueden aplicar a las propiedades con un tipo de valor o a los campos de solo lectura con un tipo de valor.Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.
Inicializador de miembro que especifica un inicializador de colección después de que el signo igual sea una inicialización de una colección incrustada.A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. En lugar de asignar una nueva colección al campo de destino, propiedad o indizador, los elementos proporcionados en el inicializador se agregan a la colección a la que hace referencia el 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. El destino debe ser de un tipo de colección que satisfaga los requisitos especificados en los inicializadores de colección.The target must be of a collection type that satisfies the requirements specified in Collection initializers.
Los argumentos de un inicializador de índice siempre se evaluarán exactamente una vez.The arguments to an index initializer will always be evaluated exactly once. Por lo tanto, aunque los argumentos acaben nunca en usarse (por ejemplo, debido a un inicializador anidado vacío), se evaluarán por sus efectos secundarios.Thus, even if the arguments end up never getting used (e.g. because of an empty nested initializer), they will be evaluated for their side effects.
La clase siguiente representa un punto con dos 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; } }
}
PointSe puede crear e inicializar una instancia de de la siguiente manera:An instance of Point can be created and initialized as follows:
Point a = new Point { X = 0, Y = 1 };
que tiene el mismo efecto quewhich has the same effect as
Point __a = new Point();
__a.X = 0;
__a.Y = 1;
Point a = __a;
donde __a es una variable temporal invisible e inaccesible en caso contrario.where __a is an otherwise invisible and inaccessible temporary variable. La clase siguiente representa un rectángulo creado a partir de dos puntos: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; } }
}
RectangleSe puede crear e inicializar una instancia de de la siguiente manera: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 tiene el mismo efecto 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;
donde __r __p1 y __p2 son variables temporales que, de lo contrario, son invisibles e inaccesibles.where __r, __p1 and __p2 are temporary variables that are otherwise invisible and inaccessible.
RectangleEl constructor de si asigna las dos instancias incrustadas PointIf Rectangle's constructor allocates the two embedded Point instances
public class Rectangle
{
Point p1 = new Point();
Point p2 = new Point();
public Point P1 { get { return p1; } }
public Point P2 { get { return p2; } }
}
la construcción siguiente se puede utilizar para inicializar las Point instancias incrustadas en lugar de asignar nuevas instancias: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 tiene el mismo efecto 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 una definición adecuada de C, el ejemplo siguiente: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] = {}
};
es equivalente a esta serie de asignaciones: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;
donde __c , etc., se generan variables que son invisibles e inaccesibles para el código fuente.where __c, etc., are generated variables that are invisible and inaccessible to the source code. Tenga en cuenta que los argumentos de [0,0] se evalúan solo una vez, y los argumentos de [1,2] se evalúan una vez, aunque nunca se utilicen.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 colecciónCollection initializers
Un inicializador de colección especifica los elementos de una colección.A collection initializer specifies the elements of a collection.
collection_initializer
: '{' element_initializer_list '}'
| '{' element_initializer_list ',' '}'
;
element_initializer_list
: element_initializer (',' element_initializer)*
;
element_initializer
: non_assignment_expression
| '{' expression_list '}'
;
expression_list
: expression (',' expression)*
;
Un inicializador de colección consta de una secuencia de inicializadores de elemento, encerrados por { } tokens y y separados por comas.A collection initializer consists of a sequence of element initializers, enclosed by { and } tokens and separated by commas. Cada inicializador de elemento especifica un elemento que se va a agregar al objeto de colección que se está inicializando y consta de una lista de expresiones delimitadas por { } tokens y y separadas por comas.Each element initializer specifies an element to be added to the collection object being initialized, and consists of a list of expressions enclosed by { and } tokens and separated by commas. Un inicializador de elemento de una sola expresión se puede escribir sin llaves, pero no puede ser una expresión de asignación para evitar la ambigüedad con los inicializadores de miembro.A single-expression element initializer can be written without braces, but cannot then be an assignment expression, to avoid ambiguity with member initializers. La non_assignment_expression Production se define en Expression.The non_assignment_expression production is defined in Expression.
A continuación se muestra un ejemplo de una expresión de creación de objeto que incluye un inicializador de colección: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 };
El objeto de colección al que se aplica un inicializador de colección debe ser de un tipo que implemente System.Collections.IEnumerable o se produzca un error en tiempo de compilación.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 en orden, el inicializador de colección invoca un Add método en el objeto de destino con la lista de expresiones del inicializador de elemento como lista de argumentos, aplicando la búsqueda de miembros normal y la resolución de sobrecarga para cada invocación.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. Por lo tanto, el objeto de colección debe tener una instancia o un método de extensión aplicable con el nombre Add de cada inicializador de elemento.Thus, the collection object must have an applicable instance or extension method with the name Add for each element initializer.
La clase siguiente representa un contacto con un nombre y una lista de números de teléfono: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; } }
}
List<Contact>Se puede crear e inicializar como se indica a continuación: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 tiene el mismo efecto 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;
donde __clist __c1 y __c2 son variables temporales que, de lo contrario, son invisibles e inaccesibles.where __clist, __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.
Expresiones de creación de matricesArray creation expressions
Un array_creation_expression se usa para crear una nueva instancia de un array_type.An array_creation_expression is used to create a new instance of an array_type.
array_creation_expression
: 'new' non_array_type '[' expression_list ']' rank_specifier* array_initializer?
| 'new' array_type array_initializer
| 'new' rank_specifier array_initializer
;
Una expresión de creación de matriz del primer formulario asigna una instancia de matriz del tipo resultante de la eliminación de cada una de las expresiones individuales de la lista de expresiones.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 ejemplo, la expresión de creación de matriz new int[10,20] genera una instancia de matriz de tipo int[,] y la expresión new int[10][,] de creación de matriz genera una matriz de 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 expresión de la lista de expresiones debe ser de tipo int , uint , long o ulong , o bien se puede convertir implícitamente a uno o varios de estos 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. El valor de cada expresión determina la longitud de la dimensión correspondiente en la instancia de matriz recién asignada.The value of each expression determines the length of the corresponding dimension in the newly allocated array instance. Dado que la longitud de una dimensión de matriz no debe ser negativa, es un error en tiempo de compilación tener un constant_expression con un valor negativo en la lista de expresiones.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.
Excepto en un contexto no seguro (contextos no seguros), no se especifica el diseño de las matrices.Except in an unsafe context (Unsafe contexts), the layout of arrays is unspecified.
Si una expresión de creación de matriz del primer formulario incluye un inicializador de matriz, cada expresión de la lista de expresiones debe ser una constante y las longitudes de rango y dimensión especificadas por la lista de expresiones deben coincidir con las del 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.
En una expresión de creación de matriz del segundo o tercer formulario, el rango del tipo de matriz o especificador de rango especificado debe coincidir con el del 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. Las longitudes de las dimensiones individuales se deducen del número de elementos de cada uno de los niveles de anidamiento correspondientes del 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. Por lo tanto, la expresiónThus, the expression
new int[,] {{0, 1}, {2, 3}, {4, 5}}
corresponde exactamente aexactly corresponds to
new int[3, 2] {{0, 1}, {2, 3}, {4, 5}}
Se hace referencia a una expresión de creación de matriz del tercer formulario como una expresión de creación de matriz con tipo * implícita _.An array creation expression of the third form is referred to as an *implicitly typed array creation expression _. Es similar a la segunda forma, salvo que el tipo de elemento de la matriz no se proporciona explícitamente, pero se determina como el mejor tipo común (encontrar el mejor tipo común de un conjunto de expresiones) del conjunto de expresiones en el 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. En el caso de una matriz multidimensional, es decir, una en la que el _rank_specifier * contiene al menos una coma, este conjunto incluye todas las expresiones que se encuentran en los array_initializer anidados.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.
Los inicializadores de matriz se describen con más detalle en inicializadores de matriz.Array initializers are described further in Array initializers.
El resultado de evaluar una expresión de creación de matriz se clasifica como un valor, es decir, una referencia a la instancia de la matriz recién asignada.The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. El procesamiento en tiempo de ejecución de una expresión de creación de matriz consta de los siguientes pasos:The run-time processing of an array creation expression consists of the following steps:
- Las expresiones de longitud de dimensión del expression_list se evalúan en orden, de izquierda a derecha.The dimension length expressions of the expression_list are evaluated in order, from left to right. Después de la evaluación de cada expresión, se realiza una conversión implícita (conversiones implícitas) en uno de los siguientes tipos
int:uint,,long,ulong.Following evaluation of each expression, an implicit conversion (Implicit conversions) to one of the following types is performed:int,uint,long,ulong. Se elige el primer tipo de esta lista para el que existe una conversión implícita.The first type in this list for which an implicit conversion exists is chosen. Si la evaluación de una expresión o la conversión implícita subsiguiente produce una excepción, no se evalúan más expresiones y no se ejecuta ningún otro paso.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. - Los valores calculados de las longitudes de dimensión se validan como se indica a continuación.The computed values for the dimension lengths are validated as follows. Si uno o varios de los valores son menores que cero,
System.OverflowExceptionse produce una excepción y no se ejecuta ningún otro paso.If one or more of the values are less than zero, aSystem.OverflowExceptionis thrown and no further steps are executed. - Se asigna una instancia de matriz con las longitudes de dimensión dadas.An array instance with the given dimension lengths is allocated. Si no hay suficiente memoria disponible para asignar la nueva instancia,
System.OutOfMemoryExceptionse produce una excepción y no se ejecuta ningún paso más.If there is not enough memory available to allocate the new instance, aSystem.OutOfMemoryExceptionis thrown and no further steps are executed. - Todos los elementos de la nueva instancia de matriz se inicializan con sus valores predeterminados (valores predeterminados).All elements of the new array instance are initialized to their default values (Default values).
- Si la expresión de creación de matriz contiene un inicializador de matriz, cada expresión del inicializador de matriz se evalúa y se asigna a su elemento de matriz correspondiente.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. Las evaluaciones y las asignaciones se realizan en el orden en el que se escriben las expresiones en el inicializador de matriz; es decir, los elementos se inicializan en el orden de índice creciente, con la dimensión situada más a la derecha aumentando primero.The evaluations and assignments are performed in the order the expressions are written in the array initializer—in other words, elements are initialized in increasing index order, with the rightmost dimension increasing first. Si la evaluación de una expresión determinada o la asignación subsiguiente al elemento de matriz correspondiente produce una excepción, no se inicializa ningún otro elemento (y los demás elementos tendrán sus valores predeterminados).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).
Una expresión de creación de matriz permite la creación de instancias de una matriz con elementos de un tipo de matriz, pero los elementos de dicha matriz se deben inicializar 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 ejemplo, la instrucciónFor example, the statement
int[][] a = new int[100][];
crea una matriz unidimensional con 100 elementos de tipo int[] .creates a single-dimensional array with 100 elements of type int[]. El valor inicial de cada elemento es null .The initial value of each element is null. No es posible que la misma expresión de creación de matriz cree también instancias de las submatrices y la instrucciónIt 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
produce un error en tiempo de compilación.results in a compile-time error. En su lugar, la creación de instancias de las submatrices debe realizarse manualmente, como enInstantiation 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];
Cuando una matriz de matrices tiene una forma "rectangular", es decir, cuando las submatrices tienen la misma longitud, es más eficaz usar una 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. En el ejemplo anterior, la creación de instancias de la matriz de matrices crea 101 objetos, una matriz externa y submatrices de 100.In the example above, instantiation of the array of arrays creates 101 objects—one outer array and 100 sub-arrays. En cambio,In contrast,
int[,] = new int[100, 5];
crea un solo objeto, una matriz bidimensional y realiza la asignación en una única instrucción.creates only a single object, a two-dimensional array, and accomplishes the allocation in a single statement.
A continuación se muestran ejemplos de expresiones de creación de matrices con tipo implícito:The following are examples of implicitly typed array creation expressions:
var a = new[] { 1, 10, 100, 1000 }; // int[]
var b = new[] { 1, 1.5, 2, 2.5 }; // double[]
var c = new[,] { { "hello", null }, { "world", "!" } }; // string[,]
var d = new[] { 1, "one", 2, "two" }; // Error
La última expresión genera un error en tiempo de compilación porque ni int ni string se pueden convertir implícitamente al otro, por lo que no hay ningún tipo común más adecuado.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. En este caso, se debe usar una expresión de creación de matriz con tipo explícito, por ejemplo, especificando el tipo object[] .An explicitly typed array creation expression must be used in this case, for example specifying the type to be object[]. Como alternativa, uno de los elementos se puede convertir a un tipo base común, que luego se convertiría en el tipo de elemento deducido.Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.
Las expresiones de creación de matrices con tipo implícito se pueden combinar con inicializadores de objeto anónimos (expresiones de creación de objetos anónimos) para crear estructuras de datos con tipos anónimos.Implicitly typed array creation expressions can be combined with anonymous object initializers (Anonymous object creation expressions) to create anonymously typed data structures. Por ejemplo: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" }
}
};
Expresiones de creación de delegadosDelegate creation expressions
Un delegate_creation_expression se usa para crear una nueva instancia de un delegate_type.A delegate_creation_expression is used to create a new instance of a delegate_type.
delegate_creation_expression
: 'new' delegate_type '(' expression ')'
;
El argumento de una expresión de creación de delegado debe ser un grupo de métodos, una función anónima o un valor del tipo en tiempo de compilación dynamic o un delegate_type.The argument of a delegate creation expression must be a method group, an anonymous function or a value of either the compile time type dynamic or a delegate_type. Si el argumento es un grupo de métodos, identifica el método y, para un método de instancia, el objeto para el que se va a crear un 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. Si el argumento es una función anónima, define directamente los parámetros y el cuerpo del método del destino del delegado.If the argument is an anonymous function it directly defines the parameters and method body of the delegate target. Si el argumento es un valor, identifica una instancia de delegado de la que se va a crear una copia.If the argument is a value it identifies a delegate instance of which to create a copy.
Si la expresión tiene el tipo en tiempo de compilación dynamic , el delegate_creation_expression está enlazado dinámicamente (enlace dinámico) y las reglas siguientes se aplican en tiempo de ejecución mediante el tipo en tiempo de ejecución de la expresión.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. De lo contrario, las reglas se aplican en tiempo de compilación.Otherwise the rules are applied at compile-time.
El procesamiento en tiempo de enlace de un delegate_creation_expression del formulario new D(E) , donde D es una delegate_type y E es una expresión, consta de los siguientes pasos:The binding-time processing of a delegate_creation_expression of the form new D(E), where D is a delegate_type and E is an expression, consists of the following steps:
- Si
Ees un grupo de métodos, la expresión de creación de delegado se procesa de la misma manera que una conversión de grupo de métodos (conversiones de grupo de métodos) deEaD.IfEis a method group, the delegate creation expression is processed in the same way as a method group conversion (Method group conversions) fromEtoD. - Si
Ees una función anónima, la expresión de creación de delegado se procesa de la misma manera que una conversión de función anónima (conversiones de funciones anónimas) deEaD.IfEis an anonymous function, the delegate creation expression is processed in the same way as an anonymous function conversion (Anonymous function conversions) fromEtoD. - Si
Ees un valor,Edebe ser compatible (declaraciones de delegado) con yDel resultado es una referencia a un delegado recién creado de tipoDque hace referencia a la misma lista de invocación queE.IfEis a value,Emust be compatible (Delegate declarations) withD, and the result is a reference to a newly created delegate of typeDthat refers to the same invocation list asE. SiEno es compatible conD, se produce un error en tiempo de compilación.IfEis not compatible withD, a compile-time error occurs.
El procesamiento en tiempo de ejecución de un delegate_creation_expression del formulario new D(E) , donde D es una delegate_type y E es una expresión, consta de los siguientes pasos:The run-time processing of a delegate_creation_expression of the form new D(E), where D is a delegate_type and E is an expression, consists of the following steps:
- Si
Ees un grupo de métodos, la expresión de creación de delegado se evalúa como una conversión de grupo de métodos (conversiones de grupo de métodos) deEaD.IfEis a method group, the delegate creation expression is evaluated as a method group conversion (Method group conversions) fromEtoD. - Si
Ees una función anónima, la creación del delegado se evalúa como una conversión de función anónima deEaD(conversiones de función anónimas).IfEis an anonymous function, the delegate creation is evaluated as an anonymous function conversion fromEtoD(Anonymous function conversions). - Si
Ees un valor de un delegate_type:IfEis a value of a delegate_type:Ese evalúa.Eis evaluated. Si esta evaluación provoca una excepción, no se ejecuta ningún paso más.If this evaluation causes an exception, no further steps are executed.- Si el valor de
Eesnull,System.NullReferenceExceptionse produce una excepción y no se ejecuta ningún paso más.If the value ofEisnull, aSystem.NullReferenceExceptionis thrown and no further steps are executed. - Se asigna una nueva instancia del tipo de delegado
D.A new instance of the delegate typeDis allocated. Si no hay suficiente memoria disponible para asignar la nueva instancia,System.OutOfMemoryExceptionse produce una excepción y no se ejecuta ningún paso más.If there is not enough memory available to allocate the new instance, aSystem.OutOfMemoryExceptionis thrown and no further steps are executed. - La nueva instancia de delegado se inicializa con la misma lista de invocación que la instancia de delegado proporcionada por
E.The new delegate instance is initialized with the same invocation list as the delegate instance given byE.
La lista de invocaciones de un delegado se determina cuando se crea una instancia del delegado y permanece constante durante toda la duración del 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. En otras palabras, no es posible cambiar las entidades a las que se puede llamar de destino de un delegado una vez que se ha creado.In other words, it is not possible to change the target callable entities of a delegate once it has been created. Cuando se combinan dos delegados o uno se quita de otro (declaraciones de delegado), se genera un nuevo delegado. no se ha cambiado el contenido de ningún delegado existente.When two delegates are combined or one is removed from another (Delegate declarations), a new delegate results; no existing delegate has its contents changed.
No es posible crear un delegado que haga referencia a una propiedad, un indexador, un operador definido por el usuario, un constructor de instancia, un destructor o un constructor 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.
Como se describió anteriormente, cuando se crea un delegado a partir de un grupo de métodos, la lista de parámetros formales y el tipo de valor devuelto del delegado determinan cuál de los métodos sobrecargados se deben seleccionar.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. En el ejemploIn 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;
}
}
el A.f campo se inicializa con un delegado que hace referencia al segundo Square método porque ese método coincide exactamente con la lista de parámetros formales y el tipo de valor devuelto de DoubleFunc .the A.f field is initialized with a delegate that refers to the second Square method because that method exactly matches the formal parameter list and return type of DoubleFunc. Si el segundo Square método no estuviera presente, se habría producido un error en tiempo de compilación.Had the second Square method not been present, a compile-time error would have occurred.
Expresiones de creación de objetos anónimosAnonymous object creation expressions
Un anonymous_object_creation_expression se usa para crear un objeto de un 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
;
Un inicializador de objeto anónimo declara un tipo anónimo y devuelve una instancia de ese tipo.An anonymous object initializer declares an anonymous type and returns an instance of that type. Un tipo anónimo es un tipo de clase sin nombre que hereda directamente de object .An anonymous type is a nameless class type that inherits directly from object. Los miembros de un tipo anónimo son una secuencia de propiedades de solo lectura que se deducen del inicializador de objeto anónimo utilizado para crear una instancia del 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. En concreto, un inicializador de objeto anónimo con el formatoSpecifically, an anonymous object initializer of the form
new { p1 = e1, p2 = e2, ..., pn = en }
declara un tipo anónimo del formulariodeclares 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() { ... }
}
donde cada Tx es el tipo de la expresión correspondiente ex .where each Tx is the type of the corresponding expression ex. La expresión utilizada en un member_declarator debe tener un tipo.The expression used in a member_declarator must have a type. Por lo tanto, se trata de un error en tiempo de compilación para que una expresión de una member_declarator sea NULL o una función anónima.Thus, it is a compile-time error for an expression in a member_declarator to be null or an anonymous function. También es un error en tiempo de compilación para que la expresión tenga un tipo no seguro.It is also a compile-time error for the expression to have an unsafe type.
El compilador genera automáticamente los nombres de un tipo anónimo y del parámetro para su Equals método, y no se puede hacer referencia a ellos en el texto del 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.
En el mismo programa, dos inicializadores de objeto anónimo que especifican una secuencia de propiedades de los mismos nombres y tipos en tiempo de compilación en el mismo orden generarán instancias del mismo 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.
En el ejemploIn the example
var p1 = new { Name = "Lawnmower", Price = 495.00 };
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2;
la asignación en la última línea se permite porque p1 y p2 son del mismo tipo anónimo.the assignment on the last line is permitted because p1 and p2 are of the same anonymous type.
Los Equals GetHashcode métodos y en los tipos anónimos invalidan los métodos heredados de y object se definen en términos de Equals y de las GetHashcode propiedades, de modo que dos instancias del mismo tipo anónimo son iguales si y solo si todas sus propiedades son iguales.The Equals and GetHashcode methods on anonymous types override the methods inherited from object, and are defined in terms of the Equals and GetHashcode of the properties, so that two instances of the same anonymous type are equal if and only if all their properties are equal.
Un declarador de miembro se puede abreviar como un nombre simple (inferencia de tipos), un acceso a miembro (comprobación en tiempo de compilación de la resolución dinámica de sobrecarga), un acceso base (acceso base) o un acceso a miembro condicional nulo (expresiones condicionales NULL como inicializadores de proyección).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). Esto se denomina inicializador de proyección y es la abreviatura de una declaración de y la asignación a una propiedad con el mismo nombre.This is called a projection initializer and is shorthand for a declaration of and assignment to a property with the same name. En concreto, los declaradores de miembros de los formulariosSpecifically, member declarators of the forms
identifier
expr.identifier
son exactamente equivalentes a lo siguiente, respectivamente:are precisely equivalent to the following, respectively:
identifier = identifier
identifier = expr.identifier
Por lo tanto, en un inicializador de proyección, el identificador selecciona tanto el valor como el campo o la propiedad a los que se asigna el valor.Thus, in a projection initializer the identifier selects both the value and the field or property to which the value is assigned. De manera intuitiva, un inicializador de proyección proyecta no solo un valor, sino también el nombre del valor.Intuitively, a projection initializer projects not just a value, but also the name of the value.
El operador typeofThe typeof operator
El typeof operador se usa para obtener el System.Type objeto para un 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
: ','
;
La primera forma de typeof_expression consta de una typeof palabra clave seguida de un tipo entre paréntesis.The first form of typeof_expression consists of a typeof keyword followed by a parenthesized type. El resultado de una expresión de este formulario es el System.Type objeto para el tipo indicado.The result of an expression of this form is the System.Type object for the indicated type. Solo hay un System.Type objeto para un tipo determinado.There is only one System.Type object for any given type. Esto significa que para un tipo T , typeof(T) == typeof(T) siempre es true.This means that for a type T, typeof(T) == typeof(T) is always true. El tipo no puede ser dynamic .The type cannot be dynamic.
La segunda forma de typeof_expression consta de una typeof palabra clave seguida de un unbound_type_name entre paréntesis.The second form of typeof_expression consists of a typeof keyword followed by a parenthesized unbound_type_name. Un unbound_type_name es muy similar a un type_name (espacio de nombres y nombres de tipo), salvo que un unbound_type_name contiene generic_dimension_specifier s donde una type_name contiene 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. Cuando el operando de una typeof_expression es una secuencia de tokens que satisface las gramáticas de unbound_type_name y type_name, es decir, cuando no contiene un generic_dimension_specifier ni un type_argument_list, la secuencia de tokens se considera una 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. El significado de un unbound_type_name se determina de la manera siguiente:The meaning of an unbound_type_name is determined as follows:
- Convierta la secuencia de tokens en un type_name reemplazando cada generic_dimension_specifier por un type_argument_list que tenga el mismo número de comas y la palabra clave
objectque 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 keywordobjectas each type_argument. - Evalúe el type_name resultante, pasando por alto todas las restricciones de parámetros de tipo.Evaluate the resulting type_name, while ignoring all type parameter constraints.
- El unbound_type_name se resuelve en el tipo genérico sin enlazar asociado con el tipo construido resultante (tipos enlazados y sin enlazar).The unbound_type_name resolves to the unbound generic type associated with the resulting constructed type (Bound and unbound types).
El resultado de la typeof_expression es el System.Type objeto para el tipo genérico sin enlazar resultante.The result of the typeof_expression is the System.Type object for the resulting unbound generic type.
La tercera forma de typeof_expression consta de una typeof palabra clave seguida de una void palabra clave entre paréntesis.The third form of typeof_expression consists of a typeof keyword followed by a parenthesized void keyword. El resultado de una expresión de este formulario es el System.Type objeto que representa la ausencia de un tipo.The result of an expression of this form is the System.Type object that represents the absence of a type. El objeto de tipo devuelto por typeof(void) es distinto del objeto de tipo devuelto para cualquier tipo.The type object returned by typeof(void) is distinct from the type object returned for any type. Este objeto de tipo especial es útil en las bibliotecas de clases que permiten la reflexión en métodos del lenguaje, donde esos métodos desean tener una manera de representar el tipo de valor devuelto de cualquier método, incluidos los métodos void, con una instancia de System.Type .This special type object is useful in class libraries that allow reflection onto methods in the language, where those methods wish to have a way to represent the return type of any method, including void methods, with an instance of System.Type.
El typeof operador se puede utilizar en un parámetro de tipo.The typeof operator can be used on a type parameter. El resultado es el System.Type objeto para el tipo en tiempo de ejecución que se ha enlazado al parámetro de tipo.The result is the System.Type object for the run-time type that was bound to the type parameter. El typeof operador también se puede usar en un tipo construido o en un tipo genérico sin enlazar (tipos enlazados y sin enlazar).The typeof operator can also be used on a constructed type or an unbound generic type (Bound and unbound types). El System.Type objeto para un tipo genérico sin enlazar no es el mismo que el System.Type objeto del tipo de instancia.The System.Type object for an unbound generic type is not the same as the System.Type object of the instance type. El tipo de instancia es siempre un tipo construido cerrado en tiempo de ejecución, por lo que su System.Type objeto depende de los argumentos de tipo en tiempo de ejecución en uso, mientras que el tipo genérico sin enlazar no tiene ningún argumento de tipo.The instance type is always a closed constructed type at run-time so its System.Type object depends on the run-time type arguments in use, while the unbound generic type has no type arguments.
En el ejemploThe 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();
}
}
genera el siguiente resultado: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]
Tenga en cuenta que int y System.Int32 son el mismo tipo.Note that int and System.Int32 are the same type.
Tenga en cuenta también que el resultado de no typeof(X<>) depende del argumento de tipo, sino del 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.
Operadores checked y uncheckedThe checked and unchecked operators
Los checked unchecked operadores y se usan para controlar el contexto de comprobación de desbordamiento para las operaciones aritméticas de tipo entero y las conversiones.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 ')'
;
El checked operador evalúa la expresión contenida en un contexto comprobado y el unchecked operador evalúa la expresión contenida en un contexto no comprobado.The checked operator evaluates the contained expression in a checked context, and the unchecked operator evaluates the contained expression in an unchecked context. Un checked_expression o unchecked_expression corresponde exactamente a un parenthesized_expression (expresiones entre paréntesis), salvo que la expresión contenida se evalúa en el contexto de comprobación de desbordamiento determinado.A checked_expression or unchecked_expression corresponds exactly to a parenthesized_expression (Parenthesized expressions), except that the contained expression is evaluated in the given overflow checking context.
El contexto de comprobación de desbordamiento también se puede controlar a través de las checked unchecked instrucciones y (las instrucciones checked y unchecked).The overflow checking context can also be controlled through the checked and unchecked statements (The checked and unchecked statements).
Las siguientes operaciones se ven afectadas por el contexto de comprobación de desbordamiento establecido por los checked unchecked operadores y y las instrucciones:The following operations are affected by the overflow checking context established by the checked and unchecked operators and statements:
- Los operadores predefinidos
++y--unarios (operadores deincremento y decremento postfijo y operadores de incremento y decremento de prefijo) cuando el operando es de un tipo entero.The predefined++and--unary operators (Postfix increment and decrement operators and Prefix increment and decrement operators), when the operand is of an integral type. -Operador unario predefinido (operador unario menos), cuando el operando es de un tipo entero.The predefined-unary operator (Unary minus operator), when the operand is of an integral type.- Los
+operadores binarios predefinidos,,-*y/(operadores aritméticos), cuando ambos operandos son de tipos enteros.The predefined+,-,*, and/binary operators (Arithmetic operators), when both operands are of integral types. - Conversiones numéricas explícitas (Conversiones numéricas explícitas) de un tipo entero a otro tipo entero, o de
floatodoublea un tipo entero.Explicit numeric conversions (Explicit numeric conversions) from one integral type to another integral type, or fromfloatordoubleto an integral type.
Cuando una de las operaciones anteriores produce un resultado que es demasiado grande para representarlo en el tipo de destino, el contexto en el que se realiza la operación controla el comportamiento 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:
- En un
checkedcontexto, si la operación es una expresión constante (expresiones constantes), se produce un error en tiempo de compilación.In acheckedcontext, if the operation is a constant expression (Constant expressions), a compile-time error occurs. De lo contrario, cuando la operación se realiza en tiempo de ejecución,System.OverflowExceptionse produce una excepción.Otherwise, when the operation is performed at run-time, aSystem.OverflowExceptionis thrown. - En un
uncheckedcontexto, el resultado se trunca descartando los bits de orden superior que no caben en el tipo de destino.In anuncheckedcontext, the result is truncated by discarding any high-order bits that do not fit in the destination type.
En el caso de las expresiones que no son constantes (expresiones que se evalúan en tiempo de ejecución) que no están incluidas en ningún checked unchecked operador o instrucción, el contexto de comprobación de desbordamiento predeterminado es unchecked a menos que los factores externos (como los modificadores de compilador y la configuración del entorno de ejecución) llamen a para su checked evaluación.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.
En el caso de expresiones constantes (expresiones que se pueden evaluar por completo en tiempo de compilación), el contexto de comprobación de desbordamiento predeterminado siempre es checked .For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. A menos que una expresión constante se coloque explícitamente en un unchecked contexto, los desbordamientos que se producen durante la evaluación en tiempo de compilación de la expresión siempre producen errores en tiempo de compilación.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.
El cuerpo de una función anónima no se ve afectado por checked o unchecked los contextos en los que se produce la función anónima.The body of an anonymous function is not affected by checked or unchecked contexts in which the anonymous function occurs.
En el ejemploIn 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
}
}
no se detectan errores en tiempo de compilación, ya que ninguna de las expresiones se puede evaluar en tiempo de compilación.no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. En tiempo de ejecución, el F método produce una excepción System.OverflowException y el G método devuelve-727379968 (los 32 bits inferiores del resultado fuera del 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). El comportamiento del H método depende del contexto de comprobación de desbordamiento predeterminado para la compilación, pero es igual o igual que F 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.
En el ejemploIn 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
}
}
los desbordamientos que se producen al evaluar las expresiones constantes en F y H provocan que se notifiquen los errores en tiempo de compilación porque las expresiones se evalúan en un 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. También se produce un desbordamiento al evaluar la expresión constante en G , pero como la evaluación tiene lugar en un unchecked contexto, el desbordamiento no se registra.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.
Los checked unchecked operadores y solo afectan al contexto de comprobación de desbordamiento para las operaciones que están contenidas textualmente en los ( tokens "" y "" ) .The checked and unchecked operators only affect the overflow checking context for those operations that are textually contained within the "(" and ")" tokens. Los operadores no tienen ningún efecto en los miembros de función que se invocan como resultado de evaluar la expresión contenida.The operators have no effect on function members that are invoked as a result of evaluating the contained expression. En el ejemploIn the example
class Test
{
static int Multiply(int x, int y) {
return x * y;
}
static int F() {
return checked(Multiply(1000000, 1000000));
}
}
el uso de checked en F no afecta a la evaluación de x * y en Multiply , por lo que x * y se evalúa en el contexto de comprobación de desbordamiento predeterminado.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.
El unchecked operador es práctico cuando se escriben constantes de los tipos enteros con signo en notación hexadecimal.The unchecked operator is convenient when writing constants of the signed integral types in hexadecimal notation. Por ejemplo:For example:
class Test
{
public const int AllBits = unchecked((int)0xFFFFFFFF);
public const int HighBit = unchecked((int)0x80000000);
}
Las dos constantes hexadecimales anteriores son de tipo uint .Both of the hexadecimal constants above are of type uint. Dado que las constantes están fuera del int intervalo, sin el unchecked operador, las conversiones a int generarán errores en tiempo de compilación.Because the constants are outside the int range, without the unchecked operator, the casts to int would produce compile-time errors.
Los checked unchecked operadores y y las instrucciones permiten a los programadores controlar determinados aspectos de algunos cálculos numéricos.The checked and unchecked operators and statements allow programmers to control certain aspects of some numeric calculations. Sin embargo, el comportamiento de algunos operadores numéricos depende de los tipos de datos de los operandos.However, the behavior of some numeric operators depends on their operands' data types. Por ejemplo, si se multiplican dos decimales, siempre se produce una excepción en el desbordamiento incluso dentro de una unchecked construcción explícita.For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked construct. Del mismo modo, si se multiplican dos floats, nunca se produce una excepción en el desbordamiento incluso dentro de una checked construcción explícita.Similarly, multiplying two floats never results in an exception on overflow even within an explicitly checked construct. Además, otros operadores nunca se ven afectados por el modo de comprobación, ya sea de forma predeterminada o explícita.In addition, other operators are never affected by the mode of checking, whether default or explicit.
Expresiones de valor predeterminadoDefault value expressions
Una expresión de valor predeterminado se usa para obtener el valor predeterminado (valores predeterminados) de un tipo.A default value expression is used to obtain the default value (Default values) of a type. Normalmente, se usa una expresión de valor predeterminado para los parámetros de tipo, ya que es posible que no se conozca si el parámetro de tipo es un tipo de valor o un tipo de referencia.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. (No existe ninguna conversión del null literal a un parámetro de tipo a menos que se sepa que el parámetro de tipo es un tipo de referencia).(No conversion exists from the null literal to a type parameter unless the type parameter is known to be a reference type.)
default_value_expression
: 'default' '(' type ')'
;
Si el tipo de un default_value_expression se evalúa en tiempo de ejecución en un tipo de referencia, el resultado se null convierte en ese 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. Si el tipo de un default_value_expression se evalúa en tiempo de ejecución en un tipo de valor, el resultado es el valor predeterminado del Value_type(constructores predeterminados).If the type in a default_value_expression evaluates at run-time to a value type, the result is the value_type's default value (Default constructors).
Un default_value_expression es una expresión constante (expresiones constantes) si el tipo es un tipo de referencia o un parámetro de tipo que se sabe que es un tipo de referencia (restricciones 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). Además, una default_value_expression es una expresión constante si el tipo es uno de los siguientes tipos de valor: sbyte , byte , short , ushort , int , uint , long , ulong ,, char ,, float double decimal , bool o cualquier tipo de enumeración.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.
Expresiones NameNameof expressions
Un nameof_expression se utiliza para obtener el nombre de una entidad de programa como una cadena de constante.A nameof_expression is used to obtain the name of a program entity as a constant string.
nameof_expression
: 'nameof' '(' named_entity ')'
;
named_entity
: simple_name
| named_entity_target '.' identifier type_argument_list?
;
named_entity_target
: 'this'
| 'base'
| named_entity
| predefined_type
| qualified_alias_member
;
Gramaticalmente hablando, el operando named_entity siempre es una expresión.Grammatically speaking, the named_entity operand is always an expression. Dado que nameof no es una palabra clave reservada, una expresión name es siempre sintácticamente ambigua con una invocación del nombre simple nameof .Because nameof is not a reserved keyword, a nameof expression is always syntactically ambiguous with an invocation of the simple name nameof. Por motivos de compatibilidad, si la búsqueda de nombres (nombres simples) del nombre nameof se realiza correctamente, la expresión se trata como un invocation_expression , independientemente de si la invocación es legal.For compatibility reasons, if a name lookup (Simple names) of the name nameof succeeds, the expression is treated as an invocation_expression -- regardless of whether the invocation is legal. En caso contrario, es un nameof_expression.Otherwise it is a nameof_expression.
El significado de la named_entity de una nameof_expression es el significado de la misma como una expresión; es decir, como un simple_name, un base_access o un 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. Sin embargo, si la búsqueda descrita en nombres simples y acceso a miembros produce un error porque se encontró un miembro de instancia en un contexto estático, un nameof_expression no genera este error.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.
Se trata de un error en tiempo de compilación para un named_entity que designa que un grupo de métodos tiene un type_argument_list.It is a compile-time error for a named_entity designating a method group to have a type_argument_list. Es un error en tiempo de compilación para que un named_entity_target tenga el tipo dynamic .It is a compile time error for a named_entity_target to have the type dynamic.
Un nameof_expression es una expresión constante de tipo string y no tiene ningún efecto en tiempo de ejecución.A nameof_expression is a constant expression of type string, and has no effect at runtime. En concreto, su named_entity no se evalúa y se omite para los fines del análisis de asignación definitiva (reglas generales para expresiones simples).Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). Su valor es el último identificador de la named_entity antes del type_argument_list final opcional, transformada de la siguiente manera:Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed in the following way:
- El prefijo "
@", si se utiliza, se quita.The prefix "@", if used, is removed. - Cada unicode_escape_sequence se transforma en el carácter Unicode correspondiente.Each unicode_escape_sequence is transformed into its corresponding Unicode character.
- Se quitan los formatting_characters .Any formatting_characters are removed.
Se trata de las mismas transformaciones aplicadas en los identificadores al probar la igualdad entre los identificadores.These are the same transformations applied in Identifiers when testing equality between identifiers.
TODO: ejemplosTODO: examples
Expresiones de método anónimoAnonymous method expressions
Una anonymous_method_expression es una de las dos formas de definir una función anónima.An anonymous_method_expression is one of two ways of defining an anonymous function. Se describen con más detalle en expresiones de función anónima.These are further described in Anonymous function expressions.
Operadores unariosUnary operators
Los ? + operadores,, - , ! , ~ , ++ , -- , CAST y await se denominan operadores unarios.The ?, +, -, !, ~, ++, --, cast, and await operators are called the unary operators.
unary_expression
: primary_expression
| null_conditional_expression
| '+' unary_expression
| '-' unary_expression
| '!' unary_expression
| '~' unary_expression
| pre_increment_expression
| pre_decrement_expression
| cast_expression
| await_expression
| unary_expression_unsafe
;
Si el operando de una unary_expression tiene el tipo en tiempo de compilación dynamic , se enlaza dinámicamente (enlace dinámico).If the operand of a unary_expression has the compile-time type dynamic, it is dynamically bound (Dynamic binding). En este caso, el tipo en tiempo de compilación del unary_expression es dynamic y la resolución que se describe a continuación se realizará en tiempo de ejecución mediante el tipo en tiempo de ejecución del 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 de NULLNull-conditional operator
El operador condicional null aplica una lista de operaciones a su operando solo si ese operando no es NULL.The null-conditional operator applies a list of operations to its operand only if that operand is non-null. De lo contrario, el resultado de aplicar el operador es null .Otherwise the result of applying the operator is null.
null_conditional_expression
: primary_expression null_conditional_operations
;
null_conditional_operations
: null_conditional_operations? '?' '.' identifier type_argument_list?
| null_conditional_operations? '?' '[' argument_list ']'
| null_conditional_operations '.' identifier type_argument_list?
| null_conditional_operations '[' argument_list ']'
| null_conditional_operations '(' argument_list? ')'
;
La lista de operaciones puede incluir operaciones de acceso a miembros y acceso a elementos (que pueden ser a su vez valores condicionales null), así como invocación.The list of operations can include member access and element access operations (which may themselves be null-conditional), as well as invocation.
Por ejemplo, la expresión a.b?[0]?.c() es un null_conditional_expression con un primary_expression a.b y null_conditional_operations ?[0] (acceso a un elemento condicional null), ?.c (acceso a miembro condicional null) y () (Invocación).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 un null_conditional_expression E con un primary_expression P , supongamos que E0 es la expresión obtenida quitando textualmente el interlineado ? de cada una de las null_conditional_operations de E que tienen uno.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. Conceptualmente, E0 es la expresión que se evaluará si ninguna de las comprobaciones nulas representadas por ? s encuentra un null .Conceptually, E0 is the expression that will be evaluated if none of the null checks represented by the ?s do find a null.
Además, supongamos que E1 es la expresión obtenida quitando textualmente el principio de ? solo el primero de la null_conditional_operations en E .Also, let E1 be the expression obtained by textually removing the leading ? from just the first of the null_conditional_operations in E. Esto puede conducir a una expresión principal (si solo había una ? ) o a otra null_conditional_expression.This may lead to a primary-expression (if there was just one ?) or to another null_conditional_expression.
Por ejemplo, si E es la expresión a.b?[0]?.c() , E0 es la expresión a.b[0].c() y E1 es la expresión a.b[0]?.c() .For example, if E is the expression a.b?[0]?.c(), then E0 is the expression a.b[0].c() and E1 is the expression a.b[0]?.c().
Si E0 se clasifica como Nothing, E se clasifica como Nothing.If E0 is classified as nothing, then E is classified as nothing. De lo contrario, E se clasifica como un valor.Otherwise E is classified as a value.
E0 y E1 se usan para determinar el significado de E :E0 and E1 are used to determine the meaning of E:
Si
Ese produce como statement_expression el significado deEes el mismo que el de la instrucciónIfEoccurs as a statement_expression the meaning ofEis the same as the statementif ((object)P != null) E1;excepto que P se evalúa solo una vez.except that P is evaluated only once.
De lo contrario, si
E0se clasifica como Nothing, se produce un error en tiempo de compilación.Otherwise, ifE0is classified as nothing a compile-time error occurs.De lo contrario,
T0será el tipo deE0.Otherwise, letT0be the type ofE0.Si
T0es un parámetro de tipo que no se sabe que es un tipo de referencia o un tipo de valor que no acepta valores NULL, se produce un error en tiempo de compilación.IfT0is a type parameter that is not known to be a reference type or a non-nullable value type, a compile-time error occurs.Si
T0es un tipo de valor que no acepta valores NULL, el tipo deEesT0?y el significado deEes el mismo queIfT0is a non-nullable value type, then the type ofEisT0?, and the meaning ofEis the same as((object)P == null) ? (T0?)null : E1excepto que
Pse evalúa solo una vez.except thatPis evaluated only once.De lo contrario, el tipo de E es T0 y el significado de E es el mismo queOtherwise the type of E is T0, and the meaning of E is the same as
((object)P == null) ? null : E1excepto que
Pse evalúa solo una vez.except thatPis evaluated only once.
Si E1 es un null_conditional_expression, estas reglas se aplican de nuevo, anidando las pruebas para null hasta que no haya más ? , y la expresión se ha reducido hasta el final de la expresión principal 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 ejemplo, si la expresión a.b?[0]?.c() se produce como una expresión de instrucción, como en la instrucción:For example, if the expression a.b?[0]?.c() occurs as a statement-expression, as in the statement:
a.b?[0]?.c();
su significado es equivalente a:its meaning is equivalent to:
if (a.b != null) a.b[0]?.c();
lo que es equivalente a:which again is equivalent to:
if (a.b != null) if (a.b[0] != null) a.b[0].c();
Salvo que a.b y a.b[0] se evalúan solo una vez.Except that a.b and a.b[0] are evaluated only once.
Si se produce en un contexto donde se usa su valor, como en:If it occurs in a context where its value is used, as in:
var x = a.b?[0]?.c();
y suponiendo que el tipo de la invocación final no es un tipo de valor que no acepta valores NULL, su significado es 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();
salvo que a.b y a.b[0] se evalúan solo una vez.except that a.b and a.b[0] are evaluated only once.
Expresiones condicionales NULL como inicializadores de proyecciónNull-conditional expressions as projection initializers
Solo se permite una expresión condicional NULL como member_declarator en un anonymous_object_creation_expression (expresiones de creación de objetos anónimos) si finaliza con un acceso a miembro (opcionalmente condicional).A null-conditional expression is only allowed as a member_declarator in an anonymous_object_creation_expression (Anonymous object creation expressions) if it ends with an (optionally null-conditional) member access. Gramaticalmente, este requisito se puede expresar de la siguiente manera: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 es un caso especial de la gramática de null_conditional_expression anterior.This is a special case of the grammar for null_conditional_expression above. La producción de member_declarator en expresiones de creación de objetos anónimos incluye solo null_conditional_member_access.The production for member_declarator in Anonymous object creation expressions then includes only null_conditional_member_access.
Expresiones condicionales NULL como expresiones de instrucciónNull-conditional expressions as statement expressions
Solo se permite una expresión condicional NULL como statement_expression (instrucciones de expresión) si finaliza con una invocación.A null-conditional expression is only allowed as a statement_expression (Expression statements) if it ends with an invocation. Gramaticalmente, este requisito se puede expresar de la siguiente manera:Grammatically, this requirement can be expressed as:
null_conditional_invocation_expression
: primary_expression null_conditional_operations '(' argument_list? ')'
;
Este es un caso especial de la gramática de null_conditional_expression anterior.This is a special case of the grammar for null_conditional_expression above. La producción de statement_expression en las instrucciones de expresión incluye solo null_conditional_invocation_expression.The production for statement_expression in Expression statements then includes only null_conditional_invocation_expression.
Operador unario másUnary plus operator
En el caso de una operación +x con el formato, se aplica la resolución de sobrecargas de operador unario (resolución de sobrecarga del operador unario) para seleccionar una implementación 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. El operando se convierte al tipo de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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. Los operadores unarios más predefinidos más son: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 uno de estos operadores, el resultado es simplemente el valor del operando.For each of these operators, the result is simply the value of the operand.
Operador unario menosUnary minus operator
En el caso de una operación -x con el formato, se aplica la resolución de sobrecargas de operador unario (resolución de sobrecarga del operador unario) para seleccionar una implementación 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. El operando se convierte al tipo de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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. Los operadores de negación predefinidos son:The predefined negation operators are:
Negación de entero:Integer negation:
int operator -(int x); long operator -(long x);El resultado se calcula restando
xde cero.The result is computed by subtractingxfrom zero. Si el valor dexes el menor valor representable del tipo de operando (-2 ^ 31 parainto-2 ^ 63 paralong), la negación matemática dexno se podrá representar en el tipo de operando.If the value ofxis the smallest representable value of the operand type (-2^31 forintor -2^63 forlong), then the mathematical negation ofxis not representable within the operand type. Si esto ocurre dentro de uncheckedcontexto,System.OverflowExceptionse produce una excepción; si se produce dentro de ununcheckedcontexto, el resultado es el valor del operando y no se registra el desbordamiento.If this occurs within acheckedcontext, aSystem.OverflowExceptionis thrown; if it occurs within anuncheckedcontext, the result is the value of the operand and the overflow is not reported.Si el operando del operador de negación es de tipo
uint, se convierte al tipolongy el tipo del resultado eslong.If the operand of the negation operator is of typeuint, it is converted to typelong, and the type of the result islong. Una excepción es la regla que permiteintescribir el valor-2147483648 (-2 ^ 31) como un literal entero decimal (literales enteros).An exception is the rule that permits theintvalue -2147483648 (-2^31) to be written as a decimal integer literal (Integer literals).Si el operando del operador de negación es de tipo
ulong, se produce un error en tiempo de compilación.If the operand of the negation operator is of typeulong, a compile-time error occurs. Una excepción es la regla que permitelongescribir el valor-9.223.372.036.854.775.808 (-2 ^ 63) como un literal entero decimal (literales enteros).An exception is the rule that permits thelongvalue -9223372036854775808 (-2^63) to be written as a decimal integer literal (Integer literals).Negación de punto flotante:Floating-point negation:
float operator -(float x); double operator -(double x);El resultado es el valor de
xcon el signo invertido.The result is the value ofxwith its sign inverted. Sixes Nan, el resultado es también Nan.Ifxis NaN, the result is also NaN.Negación decimal:Decimal negation:
decimal operator -(decimal x);El resultado se calcula restando
xde cero.The result is computed by subtractingxfrom zero. La negación decimal es equivalente a usar el operador unario menos de tipoSystem.Decimal.Decimal negation is equivalent to using the unary minus operator of typeSystem.Decimal.
Operador de negación lógica.Logical negation operator
En el caso de una operación !x con el formato, se aplica la resolución de sobrecargas de operador unario (resolución de sobrecarga del operador unario) para seleccionar una implementación 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. El operando se convierte al tipo de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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. Solo existe un operador lógico de negación predefinido:Only one predefined logical negation operator exists:
bool operator !(bool x);
Este operador calcula la negación lógica del operando: Si el operando es true , el resultado es false .This operator computes the logical negation of the operand: If the operand is true, the result is false. Si el operando es false, el resultado es true.If the operand is false, the result is true.
Operador de complemento bit a bitBitwise complement operator
En el caso de una operación ~x con el formato, se aplica la resolución de sobrecargas de operador unario (resolución de sobrecarga del operador unario) para seleccionar una implementación 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. El operando se convierte al tipo de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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. Los operadores de complemento bit a bit predefinidos son:The predefined bitwise complement operators are:
int operator ~(int x);
uint operator ~(uint x);
long operator ~(long x);
ulong operator ~(ulong x);
Para cada uno de estos operadores, el resultado de la operación es el complemento bit a bit de x .For each of these operators, the result of the operation is the bitwise complement of x.
Cada tipo de enumeración E proporciona implícitamente el siguiente operador de complemento bit a bit:Every enumeration type E implicitly provides the following bitwise complement operator:
E operator ~(E x);
El resultado de evaluar ~x , donde x es una expresión de un tipo de enumeración E con un tipo subyacente U , es exactamente igual que la evaluación (E)(~(U)x) , con la excepción de que la conversión a E siempre se realiza como si estuviera en un unchecked contexto (operadores comprobados y sin comprobar).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 y decremento prefijosPrefix increment and decrement operators
pre_increment_expression
: '++' unary_expression
;
pre_decrement_expression
: '--' unary_expression
;
El operando de una operación de incremento o decremento de prefijo debe ser una expresión clasificada como una variable, un acceso a la propiedad o un acceso a un 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. El resultado de la operación es un valor del mismo tipo que el operando.The result of the operation is a value of the same type as the operand.
Si el operando de una operación de incremento o decremento de prefijo es una propiedad o un indexador, la propiedad o el indexador deben tener un get set descriptor de acceso y.If the operand of a prefix increment or decrement operation is a property or indexer access, the property or indexer must have both a get and a set accessor. Si no es así, se produce un error en tiempo de enlace.If this is not the case, a binding-time error occurs.
La resolución de sobrecargas de operador unario (resolución de sobrecarga de operadores unarios) se aplica para seleccionar una implementación de operador específica.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. ++Existen operadores y predefinidos -- para los tipos siguientes: sbyte , byte , short , ushort , int , uint ,,, long ulong char , float , double , decimal y cualquier tipo de enumeración.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Los operadores predefinidos ++ devuelven el valor generado agregando 1 al operando y los operadores predefinidos -- devuelven el valor generado restando 1 del 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. En un checked contexto, si el resultado de esta suma o resta está fuera del intervalo del tipo de resultado y el tipo de resultado es un tipo entero o de enumeración, System.OverflowException se produce una excepción.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.
El procesamiento en tiempo de ejecución de una operación de incremento o decremento de prefijo del formulario ++x o --x consta de los siguientes pasos:The run-time processing of a prefix increment or decrement operation of the form ++x or --x consists of the following steps:
- Si
xse clasifica como una variable:Ifxis classified as a variable:xse evalúa para generar la variable.xis evaluated to produce the variable.- El operador seleccionado se invoca con el valor de
xcomo argumento.The selected operator is invoked with the value ofxas its argument. - El valor devuelto por el operador se almacena en la ubicación especificada por la evaluación de
x.The value returned by the operator is stored in the location given by the evaluation ofx. - El valor devuelto por el operador se convierte en el resultado de la operación.The value returned by the operator becomes the result of the operation.
- Si
xse clasifica como un acceso de propiedad o indizador:Ifxis classified as a property or indexer access:- La expresión de instancia (si
xno esstatic) y la lista de argumentos (sixes un acceso de indexador) asociadas axse evalúan, y los resultados se usan en lasgetsetllamadas a descriptores de acceso y posteriores.The instance expression (ifxis notstatic) and the argument list (ifxis an indexer access) associated withxare evaluated, and the results are used in the subsequentgetandsetaccessor invocations. getSe invoca el descriptor de acceso dex.Thegetaccessor ofxis invoked.- El operador seleccionado se invoca con el valor devuelto por el
getdescriptor de acceso como su argumento.The selected operator is invoked with the value returned by thegetaccessor as its argument. - El
setdescriptor de acceso dexse invoca con el valor devuelto por el operador como suvalueargumento.Thesetaccessor ofxis invoked with the value returned by the operator as itsvalueargument. - El valor devuelto por el operador se convierte en el resultado de la operación.The value returned by the operator becomes the result of the operation.
- La expresión de instancia (si
Los ++ -- operadores y también admiten la notación de postfijo (operadores de incremento y decremento de postfijo).The ++ and -- operators also support postfix notation (Postfix increment and decrement operators). Normalmente, el resultado de x++ o x-- es el valor de x antes de la operación, mientras que el resultado de ++x o --x es el valor de x después de la operación.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. En cualquier caso, x tiene el mismo valor después de la operación.In either case, x itself has the same value after the operation.
Una operator++ implementación de o operator-- se puede invocar mediante la notación de prefijo o postfijo.An operator++ or operator-- implementation can be invoked using either postfix or prefix notation. No es posible tener implementaciones de operador independientes para las dos notaciones.It is not possible to have separate operator implementations for the two notations.
Expresiones de conversiónCast expressions
Un cast_expression se utiliza para convertir explícitamente una expresión a un tipo determinado.A cast_expression is used to explicitly convert an expression to a given type.
cast_expression
: '(' type ')' unary_expression
;
Cast_expression del formulario (T)E , donde T es un tipo y E es un unary_expression, realiza una conversión explícita (conversiones explícitas) del valor de E en el 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. Si no existe una conversión explícita de E a T , se produce un error en tiempo de enlace.If no explicit conversion exists from E to T, a binding-time error occurs. De lo contrario, el resultado es el valor generado por la conversión explícita.Otherwise, the result is the value produced by the explicit conversion. El resultado siempre se clasifica como un valor, incluso si E denota una variable.The result is always classified as a value, even if E denotes a variable.
La gramática de una cast_expression conduce a ciertas ambigüedades sintácticas.The grammar for a cast_expression leads to certain syntactic ambiguities. Por ejemplo, la expresión (x)-y se puede interpretar como un cast_expression (una conversión de -y a tipo x ) o como un additive_expression combinado con un parenthesized_expression (que calcula el 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 las ambigüedades de cast_expression , existe la siguiente regla: una secuencia de uno o más tokens(espacio en blanco) entre paréntesis se considera el inicio de un cast_expression solo si se cumple al menos una de las siguientes condiciones: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:
- La secuencia de tokens es la gramática correcta para un tipo, pero no para una expresión.The sequence of tokens is correct grammar for a type, but not for an expression.
- La secuencia de tokens es la gramática correcta para un tipo, y el token que sigue inmediatamente al paréntesis de cierre es el token "
~", el token "!", el token "(", un identificador (secuencias de escape de caracteres Unicode), un literal (literales) o cualquier palabra clave (Keywords) exceptoasyis.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) exceptasandis.
El término "gramática correcta" anterior significa que la secuencia de tokens debe ajustarse a la producción gramatical concreta.The term "correct grammar" above means only that the sequence of tokens must conform to the particular grammatical production. En concreto, no se tiene en cuenta el significado real de los identificadores constituyentes.It specifically does not consider the actual meaning of any constituent identifiers. Por ejemplo, si x y y son identificadores, x.y es la gramática correcta para un tipo, incluso si x.y no denota realmente un 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.
En la regla de desambiguación se sigue que, si x y y son identificadores,, (x)y (x)(y) y (x)(-y) son cast_expression s, pero (x)-y no es, aunque x identifique un 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. Sin embargo, si x es una palabra clave que identifica un tipo predefinido (como int ), las cuatro formas son cast_expression s (porque tal palabra clave podría no ser una expresión por sí misma).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).
Expresiones AwaitAwait expressions
El operador Await se usa para suspender la evaluación de la función asincrónica envolvente hasta que se haya completado la operación asincrónica representada por el operando.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
;
Solo se permite un await_expression en el cuerpo de una función asincrónica (funciones asincrónicas).An await_expression is only allowed in the body of an async function (Async functions). Dentro de la función asincrónica envolvente más cercana, puede que no se produzca una await_expression en estos lugares:Within the nearest enclosing async function, an await_expression may not occur in these places:
- Dentro de una función anónima anidada (no asincrónica)Inside a nested (non-async) anonymous function
- Dentro del bloque de un lock_statementInside the block of a lock_statement
- En un contexto no seguroIn an unsafe context
Tenga en cuenta que no se puede producir un await_expression en la mayoría de los lugares de una query_expression, porque se transforman sintácticamente para usar expresiones lambda no asincrónicas.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 una función asincrónica, await no se puede usar como identificador.Inside of an async function, await cannot be used as an identifier. Por lo tanto, no hay ambigüedades sintácticas entre las expresiones Await y varias expresiones que intervienen en identificadores.There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. Fuera de las funciones asincrónicas, await actúa como un identificador normal.Outside of async functions, await acts as a normal identifier.
El operando de un await_expression se denomina *Task _.The operand of an await_expression is called the *task _. Representa una operación asincrónica que puede o no completarse en el momento en que se evalúa el _await_expression *.It represents an asynchronous operation that may or may not be complete at the time the _await_expression* is evaluated. El propósito del operador Await es suspender la ejecución de la función asincrónica envolvente hasta que se complete la tarea en espera y, a continuación, obtener el 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.
Expresiones que admiten AwaitAwaitable expressions
Es necesario que la tarea de una expresión Await sea Await.The task of an await expression is required to be awaitable. Una expresión t es de esperable si una de las siguientes contiene:An expression t is awaitable if one of the following holds:
tes del tipo de tiempo de compilacióndynamictis of compile time typedynamicttiene una instancia accesible o un método de extensión llamado sinGetAwaiterparámetros y sin parámetros de tipo, y un tipo de valor devuelto para el que se retienenAtodos los elementos siguientes:thas an accessible instance or extension method calledGetAwaiterwith no parameters and no type parameters, and a return typeAfor which all of the following hold:Aimplementa la interfazSystem.Runtime.CompilerServices.INotifyCompletion(en adelante conocida comoINotifyCompletionpor motivos de brevedad)Aimplements the interfaceSystem.Runtime.CompilerServices.INotifyCompletion(hereafter known asINotifyCompletionfor brevity)Atiene una propiedad de instancia accesible y legibleIsCompletedde tipoboolAhas an accessible, readable instance propertyIsCompletedof typeboolAtiene un método de instancia accesible sinGetResultparámetros y sin parámetros de tipoAhas an accessible instance methodGetResultwith no parameters and no type parameters
El propósito del GetAwaiter método es obtener un *Await _ para la tarea.The purpose of the GetAwaiter method is to obtain an *awaiter _ for the task. El tipo A se denomina el tipo _ awaiter* para la expresión Await.The type A is called the _ awaiter type* for the await expression.
El propósito de la IsCompleted propiedad es determinar si la tarea ya se ha completado.The purpose of the IsCompleted property is to determine if the task is already complete. Si es así, no es necesario suspender la evaluación.If so, there is no need to suspend evaluation.
El propósito del INotifyCompletion.OnCompleted método es registrar una "continuación" en la tarea; es decir, un delegado (de tipo System.Action ) que se invocará una vez que se complete la tarea.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.
El propósito del GetResult método es obtener el resultado de la tarea una vez que ha finalizado.The purpose of the GetResult method is to obtain the outcome of the task once it is complete. Este resultado puede ser una finalización correcta, posiblemente con un valor de resultado, o puede ser una excepción producida por el 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.
Clasificación de expresiones AwaitClassification of await expressions
La expresión await t se clasifica de la misma forma que la expresión (t).GetAwaiter().GetResult() .The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Por lo tanto, si el tipo de valor devuelto de GetResult es void , el await_expression se clasifica como Nothing.Thus, if the return type of GetResult is void, the await_expression is classified as nothing. Si tiene un tipo de valor devuelto distinto de void T , el await_expression se clasifica como un valor de tipo T .If it has a non-void return type T, the await_expression is classified as a value of type T.
Evaluación en tiempo de ejecución de expresiones AwaitRuntime evaluation of await expressions
En tiempo de ejecución, la expresión await t se evalúa como sigue:At runtime, the expression await t is evaluated as follows:
- Un Await
ase obtiene evaluando la expresión(t).GetAwaiter().An awaiterais obtained by evaluating the expression(t).GetAwaiter(). boolbSe obtiene mediante la evaluación de la expresión(a).IsCompleted.Aboolbis obtained by evaluating the expression(a).IsCompleted.- Si
besfalse, la evaluación depende de siaimplementa la interfazSystem.Runtime.CompilerServices.ICriticalNotifyCompletion(en adelante conocida comoICriticalNotifyCompletionpor motivos de brevedad).Ifbisfalsethen evaluation depends on whetheraimplements the interfaceSystem.Runtime.CompilerServices.ICriticalNotifyCompletion(hereafter known asICriticalNotifyCompletionfor brevity). Esta comprobación se realiza en el momento del enlace; es decir, en tiempo de ejecución siatiene el tipo de tiempo de compilacióndynamicy en tiempo de compilación, en caso contrario.This check is done at binding time; i.e. at runtime ifahas the compile time typedynamic, and at compile time otherwise. Serdebe indicar el delegado de reanudación (funciones asincrónicas):Letrdenote the resumption delegate (Async functions):- Si no
aimplementaICriticalNotifyCompletion, se evalúa la expresión(a as (INotifyCompletion)).OnCompleted(r).Ifadoes not implementICriticalNotifyCompletion, then the expression(a as (INotifyCompletion)).OnCompleted(r)is evaluated. - Si
aimplementaICriticalNotifyCompletion, se evalúa la expresión(a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r).Ifadoes implementICriticalNotifyCompletion, then the expression(a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r)is evaluated. - A continuación, la evaluación se suspende y el control se devuelve al autor de la llamada actual de la función asincrónica.Evaluation is then suspended, and control is returned to the current caller of the async function.
- Si no
- Inmediatamente después de (si
beratrue), o después de la invocación posterior del delegado de reanudación (siberafalse),(a).GetResult()se evalúa la expresión.Either immediately after (ifbwastrue), or upon later invocation of the resumption delegate (ifbwasfalse), the expression(a).GetResult()is evaluated. Si devuelve un valor, ese valor es el resultado de la await_expression.If it returns a value, that value is the result of the await_expression. De lo contrario, el resultado es Nothing.Otherwise the result is nothing.
La implementación de un espera de los métodos de interfaz INotifyCompletion.OnCompleted y ICriticalNotifyCompletion.UnsafeOnCompleted debe hacer que r se invoque el delegado como máximo una 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. De lo contrario, el comportamiento de la función asincrónica envolvente es indefinido.Otherwise, the behavior of the enclosing async function is undefined.
Operadores aritméticosArithmetic operators
Los * / operadores,, % , + y - se denominan 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
;
Si un operando de un operador aritmético tiene el tipo en tiempo de compilación dynamic , la expresión está enlazada dinámicamente (enlace dinámico).If an operand of an arithmetic operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). En este caso, el tipo en tiempo de compilación de la expresión es dynamic y la resolución que se describe a continuación se realiza en tiempo de ejecución mediante el tipo en tiempo de ejecución de los operandos que tienen el tipo en tiempo de compilación 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 multiplicaciónMultiplication operator
En el caso de una operación x * y con el formato, se aplica la resolución de sobrecargas del operador binario (resolución de sobrecarga del operador binario) para seleccionar una implementación 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. Los operandos se convierten en los tipos de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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.
A continuación se enumeran los operadores de multiplicación predefinidos.The predefined multiplication operators are listed below. Todos los operadores calculan el producto de x y y .The operators all compute the product of x and y.
Multiplicación de enteros: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);En un
checkedcontexto, si el producto está fuera del intervalo del tipo de resultado,System.OverflowExceptionse produce una excepción.In acheckedcontext, if the product is outside the range of the result type, aSystem.OverflowExceptionis thrown. En ununcheckedcontexto, no se informan los desbordamientos y se descartan los bits significativos de orden superior fuera del intervalo del tipo de resultado.In anuncheckedcontext, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.Multiplicación de punto flotante:Floating-point multiplication:
float operator *(float x, float y); double operator *(double x, double y);El producto se calcula de acuerdo con las reglas de aritmética de IEEE 754.The product is computed according to the rules of IEEE 754 arithmetic. En la tabla siguiente se enumeran los resultados de todas las posibles combinaciones de valores finitos distintos de cero, ceros, infinitos y NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. En la tabla,
xeyson valores finitos positivos.In the table,xandyare positive finite values.zes el resultado dex * y.zis the result ofx * y. Si el resultado es demasiado grande para el tipo de destino,zes infinito.If the result is too large for the destination type,zis infinity. Si el resultado es demasiado pequeño para el tipo de destino,zes cero.If the result is too small for the destination type,zis 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 Multiplicación decimal:Decimal multiplication:
decimal operator *(decimal x, decimal y);Si el valor resultante es demasiado grande para representarlo en el
decimalformato,System.OverflowExceptionse produce una excepción.If the resulting value is too large to represent in thedecimalformat, aSystem.OverflowExceptionis thrown. Si el valor del resultado es demasiado pequeño para representarlo en eldecimalformato, el resultado es cero.If the result value is too small to represent in thedecimalformat, the result is zero. La escala del resultado, antes de cualquier redondeo, es la suma de las escalas de los dos operandos.The scale of the result, before any rounding, is the sum of the scales of the two operands.La multiplicación decimal es equivalente a usar el operador de multiplicación de tipo
System.Decimal.Decimal multiplication is equivalent to using the multiplication operator of typeSystem.Decimal.
Operador de divisiónDivision operator
En el caso de una operación x / y con el formato, se aplica la resolución de sobrecargas del operador binario (resolución de sobrecarga del operador binario) para seleccionar una implementación 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. Los operandos se convierten en los tipos de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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.
A continuación se enumeran los operadores de división predefinidos.The predefined division operators are listed below. Todos los operadores calculan el cociente de x y y .The operators all compute the quotient of x and y.
División de enteros:Integer division:
int operator /(int x, int y); uint operator /(uint x, uint y); long operator /(long x, long y); ulong operator /(ulong x, ulong y);Si el valor del operando derecho es cero,
System.DivideByZeroExceptionse produce una excepción.If the value of the right operand is zero, aSystem.DivideByZeroExceptionis thrown.La división redondea el resultado hacia cero.The division rounds the result towards zero. Por lo tanto, el valor absoluto del resultado es el entero posible más grande que sea menor o igual que el valor absoluto del cociente de los dos 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. El resultado es cero o positivo cuando los dos operandos tienen el mismo signo y cero o negativo cuando los dos operandos tienen signos opuestos.The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs.
Si el operando izquierdo es el valor más pequeño que se representable
intolongy el operando derecho es-1, se produce un desbordamiento.If the left operand is the smallest representableintorlongvalue and the right operand is-1, an overflow occurs. En uncheckedcontexto, esto hace queSystem.ArithmeticExceptionse produzca una excepción (o una subclase de ella).In acheckedcontext, this causes aSystem.ArithmeticException(or a subclass thereof) to be thrown. En ununcheckedcontexto, se define como si seSystem.ArithmeticExceptionprodujera una excepción (o una subclase de ella) o el desbordamiento se desinforma de que el valor resultante es el del operando izquierdo.In anuncheckedcontext, 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.División de punto flotante:Floating-point division:
float operator /(float x, float y); double operator /(double x, double y);El cociente se calcula de acuerdo con las reglas de aritmética de IEEE 754.The quotient is computed according to the rules of IEEE 754 arithmetic. En la tabla siguiente se enumeran los resultados de todas las posibles combinaciones de valores finitos distintos de cero, ceros, infinitos y NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. En la tabla,
xeyson valores finitos positivos.In the table,xandyare positive finite values.zes el resultado dex / y.zis the result ofx / y. Si el resultado es demasiado grande para el tipo de destino,zes infinito.If the result is too large for the destination type,zis infinity. Si el resultado es demasiado pequeño para el tipo de destino,zes cero.If the result is too small for the destination type,zis 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 División decimal:Decimal division:
decimal operator /(decimal x, decimal y);Si el valor del operando derecho es cero,
System.DivideByZeroExceptionse produce una excepción.If the value of the right operand is zero, aSystem.DivideByZeroExceptionis thrown. Si el valor resultante es demasiado grande para representarlo en eldecimalformato,System.OverflowExceptionse produce una excepción.If the resulting value is too large to represent in thedecimalformat, aSystem.OverflowExceptionis thrown. Si el valor del resultado es demasiado pequeño para representarlo en eldecimalformato, el resultado es cero.If the result value is too small to represent in thedecimalformat, the result is zero. La escala del resultado es la menor escala que conservará un resultado igual al valor decimal que se va a representar más cercano al resultado matemático verdadero.The scale of the result is the smallest scale that will preserve a result equal to the nearest representable decimal value to the true mathematical result.La división decimal es equivalente a usar el operador de división de tipo
System.Decimal.Decimal division is equivalent to using the division operator of typeSystem.Decimal.
Operador de restoRemainder operator
En el caso de una operación x % y con el formato, se aplica la resolución de sobrecargas del operador binario (resolución de sobrecarga del operador binario) para seleccionar una implementación 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. Los operandos se convierten en los tipos de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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.
A continuación se enumeran los operadores de resto predefinidos.The predefined remainder operators are listed below. Todos los operadores calculan el resto de la división entre x y y .The operators all compute the remainder of the division between x and y.
Resto entero: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);El resultado de
x % yes el valor generado porx - (x / y) * y.The result ofx % yis the value produced byx - (x / y) * y. Siyes cero,System.DivideByZeroExceptionse produce una excepción.Ifyis zero, aSystem.DivideByZeroExceptionis thrown.Si el operando izquierdo es el menor
intlongvalor o y el operando derecho es-1,System.OverflowExceptionse produce una excepción.If the left operand is the smallestintorlongvalue and the right operand is-1, aSystem.OverflowExceptionis thrown. En ningún caso, sex % yproduce una excepción en la quex / yno se producirá una excepción.In no case doesx % ythrow an exception wherex / ywould not throw an exception.Resto de punto flotante:Floating-point remainder:
float operator %(float x, float y); double operator %(double x, double y);En la tabla siguiente se enumeran los resultados de todas las posibles combinaciones de valores finitos distintos de cero, ceros, infinitos y NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. En la tabla,
xeyson valores finitos positivos.In the table,xandyare positive finite values.zes el resultado dex % yy se calcula comox - n * y, dondenes el entero más grande posible que es menor o igual quex / y.zis the result ofx % yand is computed asx - n * y, wherenis the largest possible integer that is less than or equal tox / y. Este método de calcular el resto es análogo al que se usa para los operandos de entero, pero difiere de la definición de IEEE 754 (en quenes el entero más próximo ax / y).This method of computing the remainder is analogous to that used for integer operands, but differs from the IEEE 754 definition (in whichnis 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 Resto decimal:Decimal remainder:
decimal operator %(decimal x, decimal y);Si el valor del operando derecho es cero,
System.DivideByZeroExceptionse produce una excepción.If the value of the right operand is zero, aSystem.DivideByZeroExceptionis thrown. La escala del resultado, antes de cualquier redondeo, es el mayor de las escalas de los dos operandos y el signo del resultado, si es distinto de cero, es el mismo que el 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.El resto decimal es equivalente a usar el operador de resto de tipo
System.Decimal.Decimal remainder is equivalent to using the remainder operator of typeSystem.Decimal.
Operador de sumaAddition operator
En el caso de una operación x + y con el formato, se aplica la resolución de sobrecargas del operador binario (resolución de sobrecarga del operador binario) para seleccionar una implementación 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. Los operandos se convierten en los tipos de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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.
A continuación se enumeran los operadores de suma predefinidos.The predefined addition operators are listed below. En el caso de los tipos numéricos y de enumeración, los operadores de suma predefinidos calculan la suma de los dos operandos.For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. Cuando uno o ambos operandos son de tipo cadena, los operadores de suma predefinidos concatenan la representación de cadena de los operandos.When one or both operands are of type string, the predefined addition operators concatenate the string representation of the operands.
Suma de enteros: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);En un
checkedcontexto, si la suma está fuera del intervalo del tipo de resultado,System.OverflowExceptionse produce una excepción.In acheckedcontext, if the sum is outside the range of the result type, aSystem.OverflowExceptionis thrown. En ununcheckedcontexto, no se informan los desbordamientos y se descartan los bits significativos de orden superior fuera del intervalo del tipo de resultado.In anuncheckedcontext, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.Adición de punto flotante:Floating-point addition:
float operator +(float x, float y); double operator +(double x, double y);La suma se calcula de acuerdo con las reglas de aritmética de IEEE 754.The sum is computed according to the rules of IEEE 754 arithmetic. En la tabla siguiente se enumeran los resultados de todas las posibles combinaciones de valores finitos distintos de cero, ceros, infinitos y NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. En la tabla,
xeyson valores finitos distintos de cero yzes el resultado dex + y.In the table,xandyare nonzero finite values, andzis the result ofx + y. Sixeytienen la misma magnitud pero signos opuestos,zes cero positivo.Ifxandyhave the same magnitude but opposite signs,zis positive zero. Six + yes demasiado grande para representarlo en el tipo de destino,zes un infinito con el mismo signo quex + y.Ifx + yis too large to represent in the destination type,zis an infinity with the same sign asx + y.yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN xx zz xx xx +inf+inf -inf-inf NaNNaN +0+0 yy +0+0 +0+0 +inf+inf -inf-inf NaNNaN -0-0 yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN +inf+inf +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN NaNNaN -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN -inf-inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN Suma decimal:Decimal addition:
decimal operator +(decimal x, decimal y);Si el valor resultante es demasiado grande para representarlo en el
decimalformato,System.OverflowExceptionse produce una excepción.If the resulting value is too large to represent in thedecimalformat, aSystem.OverflowExceptionis thrown. La escala del resultado, antes de cualquier redondeo, es el mayor de las escalas de los dos operandos.The scale of the result, before any rounding, is the larger of the scales of the two operands.La suma decimal es equivalente a usar el operador de suma de tipo
System.Decimal.Decimal addition is equivalent to using the addition operator of typeSystem.Decimal.Adición de enumeración.Enumeration addition. Cada tipo de enumeración proporciona implícitamente los siguientes operadores predefinidos, donde
Ees el tipo de enumeración, yUes el tipo subyacente deE:Every enumeration type implicitly provides the following predefined operators, whereEis the enum type, andUis the underlying type ofE:E operator +(E x, U y); E operator +(U x, E y);En tiempo de ejecución, estos operadores se evalúan exactamente como
(E)((U)x + (U)y).At run-time these operators are evaluated exactly as(E)((U)x + (U)y).Concatenación de cadenas:String concatenation:
string operator +(string x, string y); string operator +(string x, object y); string operator +(object x, string y);Estas sobrecargas del operador binario
+realizan la concatenación de cadenas.These overloads of the binary+operator perform string concatenation. Si un operando de la concatenación de cadenas esnull, se sustituye una cadena vacía.If an operand of string concatenation isnull, an empty string is substituted. De lo contrario, cualquier argumento que no sea de cadena se convierte en su representación de cadena invocando elToStringmétodo virtual heredado del tipoobject.Otherwise, any non-string argument is converted to its string representation by invoking the virtualToStringmethod inherited from typeobject. SiToStringdevuelvenull, se sustituye una cadena vacía.IfToStringreturnsnull, 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 } }El resultado del operador de concatenación de cadenas es una cadena que consta de los caracteres del operando izquierdo seguidos de los caracteres del operando derecho. El operador de concatenación de cadenas nunca devuelve un
nullvalor.System.OutOfMemoryExceptionSe puede producir una excepción si no hay suficiente memoria disponible para asignar la cadena resultante.ASystem.OutOfMemoryExceptionmay be thrown if there is not enough memory available to allocate the resulting string.Combinación de delegado.Delegate combination. Cada tipo de delegado proporciona implícitamente el siguiente operador predefinido, donde
Des el tipo de delegado:Every delegate type implicitly provides the following predefined operator, whereDis the delegate type:D operator +(D x, D y);El operador binario
+realiza la combinación de delegados cuando ambos operandos son de algún tipo de delegadoD.The binary+operator performs delegate combination when both operands are of some delegate typeD. (Si los operandos tienen distintos tipos de delegado, se produce un error en tiempo de enlace). Si el primer operando esnull, el resultado de la operación es el valor del segundo operando (aunque también seanull).(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). De lo contrario, si el segundo operando esnull, el resultado de la operación es el valor del primer operando.Otherwise, if the second operand isnull, then the result of the operation is the value of the first operand. De lo contrario, el resultado de la operación es una nueva instancia de delegado que, cuando se invoca, invoca el primer operando y, a continuación, invoca el 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 obtener ejemplos de la combinación de delegados, vea operador de resta e invocación de delegado.For examples of delegate combination, see Subtraction operator and Delegate invocation. Puesto queSystem.Delegateno es un tipo de delegado,operator+no está definido para él.SinceSystem.Delegateis not a delegate type,operator+is not defined for it.
Operador de restaSubtraction operator
En el caso de una operación x - y con el formato, se aplica la resolución de sobrecargas del operador binario (resolución de sobrecarga del operador binario) para seleccionar una implementación 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. Los operandos se convierten en los tipos de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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.
A continuación se enumeran los operadores de resta predefinidos.The predefined subtraction operators are listed below. Los operadores se restann y de x .The operators all subtract y from x.
Resta de enteros: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);En un
checkedcontexto, si la diferencia está fuera del intervalo del tipo de resultado,System.OverflowExceptionse produce una excepción.In acheckedcontext, if the difference is outside the range of the result type, aSystem.OverflowExceptionis thrown. En ununcheckedcontexto, no se informan los desbordamientos y se descartan los bits significativos de orden superior fuera del intervalo del tipo de resultado.In anuncheckedcontext, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.Resta de punto flotante:Floating-point subtraction:
float operator -(float x, float y); double operator -(double x, double y);La diferencia se calcula de acuerdo con las reglas de aritmética de IEEE 754.The difference is computed according to the rules of IEEE 754 arithmetic. En la tabla siguiente se enumeran los resultados de todas las posibles combinaciones de valores finitos distintos de cero, ceros, infinitos y Nan.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaNs. En la tabla,
xeyson valores finitos distintos de cero yzes el resultado dex - y.In the table,xandyare nonzero finite values, andzis the result ofx - y. Sixeyson iguales,zes cero positivo.Ifxandyare equal,zis positive zero. Six - yes demasiado grande para representarlo en el tipo de destino,zes un infinito con el mismo signo quex - y.Ifx - yis too large to represent in the destination type,zis an infinity with the same sign asx - y.yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN xx zz xx xx -inf-inf +inf+inf NaNNaN +0+0 -y-y +0+0 +0+0 -inf-inf +inf+inf NaNNaN -0-0 -y-y -0-0 +0+0 -inf-inf +inf+inf NaNNaN +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN +inf+inf NaNNaN -inf-inf -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN Resta decimal:Decimal subtraction:
decimal operator -(decimal x, decimal y);Si el valor resultante es demasiado grande para representarlo en el
decimalformato,System.OverflowExceptionse produce una excepción.If the resulting value is too large to represent in thedecimalformat, aSystem.OverflowExceptionis thrown. La escala del resultado, antes de cualquier redondeo, es el mayor de las escalas de los dos operandos.The scale of the result, before any rounding, is the larger of the scales of the two operands.La resta decimal es equivalente a usar el operador de resta de tipo
System.Decimal.Decimal subtraction is equivalent to using the subtraction operator of typeSystem.Decimal.Resta de enumeración.Enumeration subtraction. Cada tipo de enumeración proporciona implícitamente el siguiente operador predefinido, donde
Ees el tipo de enumeración, yUes el tipo subyacente deE:Every enumeration type implicitly provides the following predefined operator, whereEis the enum type, andUis the underlying type ofE:U operator -(E x, E y);Este operador se evalúa exactamente como
(U)((U)x - (U)y).This operator is evaluated exactly as(U)((U)x - (U)y). En otras palabras, el operador calcula la diferencia entre los valores ordinales dexyy, y el tipo del resultado es el tipo subyacente de la enumeración.In other words, the operator computes the difference between the ordinal values ofxandy, and the type of the result is the underlying type of the enumeration.E operator -(E x, U y);Este operador se evalúa exactamente como
(E)((U)x - y).This operator is evaluated exactly as(E)((U)x - y). En otras palabras, el operador resta un valor del tipo subyacente de la enumeración, lo que produce un valor de la enumeración.In other words, the operator subtracts a value from the underlying type of the enumeration, yielding a value of the enumeration.Eliminación de delegados.Delegate removal. Cada tipo de delegado proporciona implícitamente el siguiente operador predefinido, donde
Des el tipo de delegado:Every delegate type implicitly provides the following predefined operator, whereDis the delegate type:D operator -(D x, D y);El operador binario
-realiza la eliminación del delegado cuando ambos operandos son de algún tipo de delegadoD.The binary-operator performs delegate removal when both operands are of some delegate typeD. Si los operandos tienen distintos tipos de delegado, se produce un error en tiempo de enlace.If the operands have different delegate types, a binding-time error occurs. Si el primer operando esnull, el resultado de la operación esnull.If the first operand isnull, the result of the operation isnull. De lo contrario, si el segundo operando esnull, el resultado de la operación es el valor del primer operando.Otherwise, if the second operand isnull, then the result of the operation is the value of the first operand. De lo contrario, ambos operandos representan listas de invocación (declaraciones de delegado) que tienen una o más entradas y el resultado es una nueva lista de invocación que se compone de la lista del primer operando con las entradas del segundo operando que se han quitado, siempre que la lista del segundo operando sea una sublista contigua adecuada de la primera.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 la igualdad de la lista, las entradas correspondientes se comparan como para el operador de igualdad de delegado (operadores de igualdad de delegado)). De lo contrario, el resultado es el valor del operando izquierdo.(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. En el proceso no se cambia ninguna de las listas de operandos.Neither of the operands' lists is changed in the process. Si la lista del segundo operando coincide con varias sublistas de entradas contiguas de la lista del primer operando, se quita la sublista coincidente situada más a la derecha de las entradas contiguas.If the second operand's list matches multiple sublists of contiguous entries in the first operand's list, the right-most matching sublist of contiguous entries is removed. Si la eliminación da como resultado una lista vacía, el resultado esnull.If removal results in an empty list, the result isnull. Por ejemplo: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 de desplazamientoShift operators
Los << >> operadores y se utilizan para realizar operaciones de desplazamiento de bits.The << and >> operators are used to perform bit shifting operations.
shift_expression
: additive_expression
| shift_expression '<<' additive_expression
| shift_expression right_shift additive_expression
;
Si un operando de una shift_expression tiene el tipo en tiempo de compilación dynamic , la expresión está enlazada dinámicamente (enlace dinámico).If an operand of a shift_expression has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). En este caso, el tipo en tiempo de compilación de la expresión es dynamic y la resolución que se describe a continuación se realiza en tiempo de ejecución mediante el tipo en tiempo de ejecución de los operandos que tienen el tipo en tiempo de compilación 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 una operación con el formato x << count o x >> count , se aplica la resolución de sobrecargas del operador binario (resolución de sobrecarga del operador binario) para seleccionar una implementación 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. Los operandos se convierten en los tipos de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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.
Al declarar un operador de desplazamiento sobrecargado, el tipo del primer operando siempre debe ser la clase o el struct que contiene la declaración del operador y el tipo del segundo operando siempre debe 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.
A continuación se enumeran los operadores de desplazamiento predefinidos.The predefined shift operators are listed below.
Desplazar a la izquierda: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);El
<<operador se desplaza a laxizquierda un número de bits calculado como se describe a continuación.The<<operator shiftsxleft by a number of bits computed as described below.Los bits de orden superior fuera del intervalo del tipo de resultado de
xse descartan, los bits restantes se desplazan a la izquierda y las posiciones de bits vacías de orden inferior se establecen en cero.The high-order bits outside the range of the result type ofxare discarded, the remaining bits are shifted left, and the low-order empty bit positions are set to zero.Desplazamiento a la derecha: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);El
>>operador se desplaza a laxderecha un número de bits calculado como se describe a continuación.The>>operator shiftsxright by a number of bits computed as described below.Cuando
xes de tipointolong, los bits de orden inferior dexse descartan, los bits restantes se desplazan a la derecha y las posiciones de bits vacías de orden superior se establecen en cero sixno es negativo y se establecen en uno sixes negativo.Whenxis of typeintorlong, the low-order bits ofxare discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero ifxis non-negative and set to one ifxis negative.Cuando
xes de tipouintoulong, los bits de orden inferior dexse descartan, los bits restantes se desplazan a la derecha y las posiciones de bits vacías de orden superior se establecen en cero.Whenxis of typeuintorulong, the low-order bits ofxare discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero.
En el caso de los operadores predefinidos, el número de bits que se va a desplazar se calcula de la manera siguiente:For the predefined operators, the number of bits to shift is computed as follows:
- Cuando el tipo de
xesintouint, el número de turnos viene dado por los cinco bits de orden inferior decount.When the type ofxisintoruint, the shift count is given by the low-order five bits ofcount. En otras palabras, el número de turnos se calcula a partir decount & 0x1F.In other words, the shift count is computed fromcount & 0x1F. - Cuando el tipo de
xeslongoulong, el recuento de desplazamiento lo proporcionan los seis bits de orden inferior decount.When the type ofxislongorulong, the shift count is given by the low-order six bits ofcount. En otras palabras, el número de turnos se calcula a partir decount & 0x3F.In other words, the shift count is computed fromcount & 0x3F.
Si el número de turnos resultante es cero, los operadores de desplazamiento simplemente devuelven el valor de x .If the resulting shift count is zero, the shift operators simply return the value of x.
Las operaciones de desplazamiento nunca causan desbordamientos y producen los mismos resultados en checked y unchecked contextos.Shift operations never cause overflows and produce the same results in checked and unchecked contexts.
Cuando el operando izquierdo del >> operador es de un tipo entero con signo, el operador realiza un desplazamiento aritmético a la derecha, donde el valor del bit más significativo (el bit de signo) del operando se propaga a las posiciones de bits vacías de orden 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. Cuando el operando izquierdo del >> operador es de un tipo entero sin signo, el operador realiza un desplazamiento lógico derecho en el que las posiciones de bits vacías de orden superior siempre se establecen en cero.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 realizar la operación opuesta a la que se infiere del tipo de operando, se pueden usar conversiones explícitas.To perform the opposite operation of that inferred from the operand type, explicit casts can be used. Por ejemplo, si x es una variable de tipo int , la operación unchecked((int)((uint)x >> y)) realiza un desplazamiento lógico a la derecha 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 comprobación de tipos y relacionalesRelational and type-testing operators
Los == != operadores,, < ,, > <= , >= is y as se denominan operadores relacionales y de prueba de tipos.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
;
El is operador se describe en el operador is y el as operador se describe en el operador as.The is operator is described in The is operator and the as operator is described in The as operator.
Los == != operadores, < , > , <= y >= son operadores de comparación.The ==, !=, <, >, <= and >= operators are comparison operators.
Si un operando de un operador de comparación tiene el tipo en tiempo de compilación dynamic , la expresión está enlazada dinámicamente (enlace dinámico).If an operand of a comparison operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). En este caso, el tipo en tiempo de compilación de la expresión es dynamic y la resolución que se describe a continuación se realiza en tiempo de ejecución mediante el tipo en tiempo de ejecución de los operandos que tienen el tipo en tiempo de compilación 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 una operación con el formato x OP y , donde OP es un operador de comparación, se aplica la resolución de sobrecarga (resolución de sobrecarga del operador binario) para seleccionar una implementación 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. Los operandos se convierten en los tipos de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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.
Los operadores de comparación predefinidos se describen en las secciones siguientes.The predefined comparison operators are described in the following sections. Todos los operadores de comparación predefinidos devuelven un resultado de tipo bool , tal y como se describe en la tabla siguiente.All predefined comparison operators return a result of type bool, as described in the following table.
| OperaciónOperation | ResultadoResult |
|---|---|
x == y |
true``xes si es igual a y ; false en caso contrario, es.true if x is equal to y, false otherwise |
x != y |
true``xes si no es igual a y ; false en caso contrario, es.true if x is not equal to y, false otherwise |
x < y |
true si x es menor que y, false en caso contrariotrue if x is less than y, false otherwise |
x > y |
true si x es mayor que y, false en caso contrariotrue if x is greater than y, false otherwise |
x <= y |
true si x es menor o igual que y, false en caso contrariotrue if x is less than or equal to y, false otherwise |
x >= y |
true si x es mayor o igual que y, false en caso contrariotrue if x is greater than or equal to y, false otherwise |
Operadores de comparación de enterosInteger comparison operators
Los operadores de comparación de enteros predefinidos son: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 uno de estos operadores compara los valores numéricos de los dos operandos de tipo entero y devuelve un bool valor que indica si la relación concreta es true o 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 comparación de punto flotanteFloating-point comparison operators
Los operadores de comparación de punto flotante predefinidos son: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);
Los operadores comparan los operandos según las reglas del estándar IEEE 754:The operators compare the operands according to the rules of the IEEE 754 standard:
Si alguno de los operandos es NaN, el resultado es
falsepara todos los operadores excepto!=, para los que el resultado estrue.If either operand is NaN, the result isfalsefor all operators except!=, for which the result istrue. Para dos operandos cualesquiera,x != ysiempre genera el mismo resultado que!(x == y).For any two operands,x != yalways produces the same result as!(x == y). Sin embargo, cuando uno o ambos operandos son Nan, los<operadores,,><=y>=no producen los mismos resultados que la negación lógica del operador opuesto.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 ejemplo, si uno de los valores dexyyes Nan,x < yesfalse, pero!(x >= y)estrue.For example, if either ofxandyis NaN, thenx < yisfalse, but!(x >= y)istrue.Cuando ninguno de los operandos es NaN, los operadores comparan los valores de los dos operandos de punto flotante con respecto a la ordenación.When neither operand is NaN, the operators compare the values of the two floating-point operands with respect to the ordering
-inf < -max < ... < -min < -0.0 == +0.0 < +min < ... < +max < +infdonde
minymaxson los valores finitos positivos más pequeños y mayores que se pueden representar en el formato de punto flotante dado.whereminandmaxare the smallest and largest positive finite values that can be represented in the given floating-point format. Los efectos importantes de este orden son:Notable effects of this ordering are:- Los ceros negativos y positivos se consideran iguales.Negative and positive zeros are considered equal.
- Un infinito negativo se considera menor que todos los demás valores, pero es igual a otro infinito negativo.A negative infinity is considered less than all other values, but equal to another negative infinity.
- Un infinito positivo se considera mayor que el resto de los valores, pero es igual a otro infinito positivo.A positive infinity is considered greater than all other values, but equal to another positive infinity.
Operadores de comparación decimalDecimal comparison operators
Los operadores de comparación decimal predefinidos son: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 uno de estos operadores compara los valores numéricos de los dos operandos decimales y devuelve un bool valor que indica si la relación concreta es true o 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 comparación decimal es equivalente a usar el operador relacional o de igualdad correspondiente de tipo System.Decimal .Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal.
Operadores de igualdad booleanosBoolean equality operators
Los operadores de igualdad booleano predefinidos son:The predefined boolean equality operators are:
bool operator ==(bool x, bool y);
bool operator !=(bool x, bool y);
El resultado de == es true si x y y son true o si x y y son false .The result of == is true if both x and y are true or if both x and y are false. De lo contrario, el resultado es false.Otherwise, the result is false.
El resultado de != es false si x y y son true o si x y y son false .The result of != is false if both x and y are true or if both x and y are false. De lo contrario, el resultado es true.Otherwise, the result is true. Cuando los operandos son de tipo bool , el != operador produce el mismo resultado que el ^ operador.When the operands are of type bool, the != operator produces the same result as the ^ operator.
Operadores de comparación de enumeraciónEnumeration comparison operators
Cada tipo de enumeración proporciona implícitamente los siguientes operadores de comparación 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);
El resultado de evaluar x op y , donde x y y son expresiones de un tipo de enumeración E con un tipo subyacente U , y op es uno de los operadores de comparación, es exactamente igual que evaluar ((U)x) op ((U)y) .The result of evaluating x op y, where x and y are expressions of an enumeration type E with an underlying type U, and op is one of the comparison operators, is exactly the same as evaluating ((U)x) op ((U)y). En otras palabras, los operadores de comparación de tipos de enumeración simplemente comparan los valores enteros subyacentes de los dos operandos.In other words, the enumeration type comparison operators simply compare the underlying integral values of the two operands.
Operadores de igualdad de tipos de referenciaReference type equality operators
Los operadores de igualdad de tipos de referencia predefinidos son:The predefined reference type equality operators are:
bool operator ==(object x, object y);
bool operator !=(object x, object y);
Los operadores devuelven el resultado de comparar las dos referencias de igualdad o de no igualdad.The operators return the result of comparing the two references for equality or non-equality.
Puesto que los operadores de igualdad de tipos de referencia predefinidos aceptan operandos de tipo object , se aplican a todos los tipos que no declaran operator == operator != los miembros y aplicables.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 el contrario, todos los operadores de igualdad definidos por el usuario aplicables ocultan de forma eficaz los operadores de igualdad de tipos de referencia predefinidos.Conversely, any applicable user-defined equality operators effectively hide the predefined reference type equality operators.
Los operadores de igualdad de tipos de referencia predefinidos requieren uno de los siguientes:The predefined reference type equality operators require one of the following:
- Ambos operandos son un valor de un tipo conocido como reference_type o literal
null.Both operands are a value of a type known to be a reference_type or the literalnull. Además, existe una conversión de referencia explícita (conversiones de referencia explícitas) desde el tipo de uno de los operandos al tipo del otro operando.Furthermore, an explicit reference conversion (Explicit reference conversions) exists from the type of either operand to the type of the other operand. - Un operando es un valor de
TtipoT, donde es un type_parameter y el otro operando es el literalnull.One operand is a value of typeTwhereTis a type_parameter and the other operand is the literalnull. Además, noTtiene la restricción de tipo de valor.FurthermoreTdoes not have the value type constraint.
A menos que se cumpla una de estas condiciones, se produce un error en tiempo de enlace.Unless one of these conditions are true, a binding-time error occurs. Las implicaciones destacadas de estas reglas son:Notable implications of these rules are:
- Es un error en tiempo de enlace usar los operadores de igualdad de tipos de referencia predefinidos para comparar dos referencias que se sabe que son diferentes en tiempo de enlace.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 ejemplo, si los tipos en tiempo de enlace de los operandos son dos tipos de clase
AyB, y si no seABderivan de la otra, sería imposible que los dos operandos hagan referencia al mismo objeto.For example, if the binding-time types of the operands are two class typesAandB, and if neitherAnorBderives from the other, then it would be impossible for the two operands to reference the same object. Por lo tanto, la operación se considera un error en tiempo de enlace.Thus, the operation is considered a binding-time error. - Los operadores de igualdad de tipos de referencia predefinidos no permiten comparar los operandos de tipo de valor.The predefined reference type equality operators do not permit value type operands to be compared. Por lo tanto, a menos que un tipo de estructura declare sus propios operadores de igualdad, no es posible comparar valores de ese tipo de estructura.Therefore, unless a struct type declares its own equality operators, it is not possible to compare values of that struct type.
- Los operadores de igualdad de tipos de referencia predefinidos nunca provocan que se produzcan operaciones de conversión boxing para sus operandos.The predefined reference type equality operators never cause boxing operations to occur for their operands. No tendría sentido realizar estas operaciones de conversión boxing, ya que las referencias a las instancias de conversión boxing recién asignadas serían necesariamente distintas de las demás referencias.It would be meaningless to perform such boxing operations, since references to the newly allocated boxed instances would necessarily differ from all other references.
- Si un operando de un tipo de parámetro de tipo
Tse compara connully el tipo en tiempo de ejecución deTes un tipo de valor, el resultado de la comparación esfalse.If an operand of a type parameter typeTis compared tonull, and the run-time type ofTis a value type, the result of the comparison isfalse.
En el ejemplo siguiente se comprueba si un argumento de un tipo de parámetro de tipo sin restricciones es null .The following example checks whether an argument of an unconstrained type parameter type is null.
class C<T>
{
void F(T x) {
if (x == null) throw new ArgumentNullException();
...
}
}
La x == null construcción se permite aunque T pueda representar un tipo de valor y el resultado se define simplemente como false cuando T es un 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.
En el caso de una operación de la forma x == y o x != y , si es aplicable operator == o operator != existe, las reglas de resolución de sobrecarga del operador (resolución de sobrecarga del operador binario) seleccionarán ese operador en lugar del operador de igualdad de tipos de referencia 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. Sin embargo, siempre es posible seleccionar el operador de igualdad de tipos de referencia predefinido convirtiendo explícitamente uno o ambos operandos al 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. En el ejemploThe 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);
}
}
genera el resultadoproduces the output
True
False
False
False
Las s t variables y hacen referencia a dos string instancias distintas que contienen los mismos caracteres.The s and t variables refer to two distinct string instances containing the same characters. La primera comparación genera resultados True porque el operador de igualdad de cadena predefinido (operadores de igualdad de cadena) está seleccionado cuando ambos operandos son de 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. El resto de las comparaciones False se generan porque el operador de igualdad de tipos de referencia predefinido se selecciona cuando uno o ambos operandos son del 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.
Tenga en cuenta que la técnica anterior no es significativa para los tipos de valor.Note that the above technique is not meaningful for value types. En el ejemploThe example
class Test
{
static void Main() {
int i = 123;
int j = 123;
System.Console.WriteLine((object)i == (object)j);
}
}
Falsese produce porque las conversiones crean referencias a dos instancias independientes de valores de conversión boxing int .outputs False because the casts create references to two separate instances of boxed int values.
Operadores de igualdad de cadenasString equality operators
Los operadores de igualdad de cadena predefinidos son:The predefined string equality operators are:
bool operator ==(string x, string y);
bool operator !=(string x, string y);
Dos string valores se consideran iguales cuando se cumple una de las siguientes condiciones:Two string values are considered equal when one of the following is true:
- Ambos valores son
null.Both values arenull. - Ambos valores son referencias no nulas a instancias de cadena que tienen longitudes idénticas y caracteres idénticos en cada posición de carácter.Both values are non-null references to string instances that have identical lengths and identical characters in each character position.
Los operadores de igualdad de cadena comparan valores de cadena en lugar de referencias de cadena.The string equality operators compare string values rather than string references. Cuando dos instancias de cadena independientes contienen exactamente la misma secuencia de caracteres, los valores de las cadenas son iguales, pero las referencias son 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. Como se describe en operadores de igualdad de tipos de referencia, los operadores de igualdad de tipos de referencia se pueden usar para comparar referencias de cadena en lugar de valores de cadena.As described in Reference type equality operators, the reference type equality operators can be used to compare string references instead of string values.
Operadores de igualdad de delegadoDelegate equality operators
Cada tipo de delegado proporciona implícitamente los siguientes operadores de comparación 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);
Dos instancias de delegado se consideran iguales como se indica a continuación:Two delegate instances are considered equal as follows:
- Si alguna de las instancias de delegado es
null, son iguales si y solo si ambos sonnull.If either of the delegate instances isnull, they are equal if and only if both arenull. - Si los delegados tienen un tipo diferente en tiempo de ejecución, nunca son iguales.If the delegates have different run-time type they are never equal.
- Si ambas instancias de delegado tienen una lista de invocaciones (declaraciones de delegado), esas instancias son iguales si y solo si sus listas de invocación tienen la misma longitud, y cada entrada de una lista de invocación de una de ellas es igual (tal como se define a continuación) a la entrada correspondiente, en orden, en la lista de invocación de otro.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.
Las siguientes reglas rigen la igualdad de las entradas de la lista de invocación:The following rules govern the equality of invocation list entries:
- Si dos entradas de la lista de invocación hacen referencia al mismo método estático, las entradas son iguales.If two invocation list entries both refer to the same static method then the entries are equal.
- Si dos entradas de la lista de invocación hacen referencia al mismo método no estático en el mismo objeto de destino (tal y como se define en los operadores de igualdad de referencia), las entradas son iguales.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.
- Las entradas de la lista de invocación generadas a partir de la evaluación de anonymous_method_expression s o lambda_expression con el mismo conjunto (posiblemente vacío) de las instancias de variables externas capturadas están permitidas (pero no necesarias).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 igualdad y nullEquality operators and null
Los == != operadores y permiten que un operando sea un valor de un tipo que acepta valores NULL y el otro para ser el null literal, incluso si no existe ningún operador predefinido o definido por el usuario (en formato sin elevación o elevado) para la operación.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 una operación de uno de los formulariosFor an operation of one of the forms
x == null
null == x
x != null
null != x
donde x es una expresión de un tipo que acepta valores NULL, si la resolución de sobrecarga del operador (resolución de sobrecarga del operador binario) no encuentra un operador aplicable, el resultado se calcula en su lugar a partir de la HasValue propiedad 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. En concreto, las dos primeras formas se traducen en !x.HasValue y se traducen las dos últimas x.HasValue .Specifically, the first two forms are translated into !x.HasValue, and last two forms are translated into x.HasValue.
El operador isThe is operator
El is operador se usa para comprobar dinámicamente si el tipo en tiempo de ejecución de un objeto es compatible con un tipo determinado.The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. El resultado de la operación E is T , donde E es una expresión y T es un tipo, es un valor booleano que indica si se E puede convertir correctamente al tipo T mediante una conversión de referencia, una conversión boxing o una conversión 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. La operación se evalúa como sigue, después de que se hayan sustituido los argumentos de tipo para todos los parámetros de tipo:The operation is evaluated as follows, after type arguments have been substituted for all type parameters:
- Si
Ees una función anónima, se produce un error en tiempo de compilaciónIfEis an anonymous function, a compile-time error occurs - Si
Ees un grupo de métodos o elnullliteral, si el tipo deEes un tipo de referencia o un tipo que acepta valores NULL y el valor deEes null, el resultado es false.IfEis a method group or thenullliteral, of if the type ofEis a reference type or a nullable type and the value ofEis null, the result is false. - En caso contrario, deje que
Drepresente el tipo dinámico de de laEsiguiente manera:Otherwise, letDrepresent the dynamic type ofEas follows:- Si el tipo de
Ees un tipo de referencia,Des el tipo en tiempo de ejecución de la referencia de instancia deE.If the type ofEis a reference type,Dis the run-time type of the instance reference byE. - Si el tipo de
Ees un tipo que acepta valores NULL,Des el tipo subyacente de ese tipo que acepta valores NULL.If the type ofEis a nullable type,Dis the underlying type of that nullable type. - Si el tipo de
Ees un tipo de valor que no acepta valores NULL,Des el tipo deE.If the type ofEis a non-nullable value type,Dis the type ofE.
- Si el tipo de
- El resultado de la operación depende de y de la manera
DTsiguiente:The result of the operation depends onDandTas follows:- Si
Tes un tipo de referencia, el resultado es true siDyTson del mismo tipo, siDes un tipo de referencia y una conversión de referencia implícita deDaTEXISTS, o siDes un tipo de valor y una conversión boxing deDaTEXISTS.IfTis a reference type, the result is true ifDandTare the same type, ifDis a reference type and an implicit reference conversion fromDtoTexists, or ifDis a value type and a boxing conversion fromDtoTexists. - Si
Tes un tipo que acepta valores NULL, el resultado es true siDes el tipo subyacente deT.IfTis a nullable type, the result is true ifDis the underlying type ofT. - Si
Tes un tipo de valor que no acepta valores NULL, el resultado es true siDyTson del mismo tipo.IfTis a non-nullable value type, the result is true ifDandTare the same type. - De lo contrario, el resultado es false.Otherwise, the result is false.
- Si
Tenga en cuenta que las conversiones definidas por el usuario no se tienen en cuenta por el is operador.Note that user defined conversions, are not considered by the is operator.
El operador asThe as operator
El as operador se usa para convertir explícitamente un valor en un tipo de referencia determinado o un tipo que acepta valores NULL.The as operator is used to explicitly convert a value to a given reference type or nullable type. A diferencia de una expresión de conversión (expresiones de conversión), el as operador nunca produce una excepción.Unlike a cast expression (Cast expressions), the as operator never throws an exception. En su lugar, si la conversión indicada no es posible, el valor resultante es null .Instead, if the indicated conversion is not possible, the resulting value is null.
En una operación del formulario E as T , E debe ser una expresión y T debe ser un tipo de referencia, un parámetro de tipo conocido como un tipo de referencia o un tipo que acepta valores NULL.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. Además, al menos uno de los siguientes debe ser true o, de lo contrario, se producirá un error en tiempo de compilación:Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:
- Una identidad (conversión de identidad), implícita que acepta valores NULL (conversiones implícitas que aceptan valores NULL), referencia implícita (conversiones dereferencias implícitas), conversión boxing (conversiones boxing), conversión explícita de valores NULL (conversionesexplícitas que aceptan valores NULL), referencia explícita (conversiones dereferencia explícita) o conversión unboxing (conversionesunboxing) de
EaT.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 fromEtoT. - El tipo de
EoTes un tipo abierto.The type ofEorTis an open type. Ees elnullliteral.Eis thenullliteral.
Si el tipo en tiempo de compilación de E no es dynamic , la operación E as T produce el mismo 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
salvo que E solo se evalúa una vez.except that E is only evaluated once. Se puede esperar que el compilador optimice E as T para realizar como máximo una comprobación de tipos dinámicos en lugar de las dos comprobaciones de tipos dinámicos implícitas por la expansión anterior.The compiler can be expected to optimize E as T to perform at most one dynamic type check as opposed to the two dynamic type checks implied by the expansion above.
Si el tipo en tiempo de compilación de E es dynamic , a diferencia del operador de conversión, el as operador no está enlazado dinámicamente (enlace dinámico).If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound (Dynamic binding). Por lo tanto, la expansión en este caso es:Therefore the expansion in this case is:
E is T ? (T)(object)(E) : (T)null
Tenga en cuenta que algunas conversiones, como las conversiones definidas por el usuario, no son posibles con el as operador y deben realizarse en su lugar mediante expresiones de conversión.Note that some conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.
En el ejemploIn 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
}
}
Tse sabe que el parámetro de tipo de G es un tipo de referencia, porque tiene la restricción de clase.the type parameter T of G is known to be a reference type, because it has the class constraint. USin embargo, el parámetro de tipo de H no es; por lo tanto, no se permite el uso del as operador en H .The type parameter U of H is not however; hence the use of the as operator in H is disallowed.
Operadores lógicosLogical operators
Los & ^ operadores, y | se denominan 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
;
Si un operando de un operador lógico tiene el tipo en tiempo de compilación dynamic , la expresión está enlazada dinámicamente (enlace dinámico).If an operand of a logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). En este caso, el tipo en tiempo de compilación de la expresión es dynamic y la resolución que se describe a continuación se realiza en tiempo de ejecución mediante el tipo en tiempo de ejecución de los operandos que tienen el tipo en tiempo de compilación 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.
En el caso de una operación con el formato x op y , donde op es uno de los operadores lógicos, se aplica la resolución de sobrecarga (resolución de sobrecarga del operador binario) para seleccionar una implementación 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. Los operandos se convierten en los tipos de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del 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.
En las secciones siguientes se describen los operadores lógicos predefinidos.The predefined logical operators are described in the following sections.
Operadores lógicos enterosInteger logical operators
Los operadores lógicos de enteros predefinidos son: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);
El & operador calcula el lógico bit AND a bit de los dos operandos, el | operador calcula el operador lógico bit OR a bit de los dos operandos y el ^ operador calcula la lógica exclusiva bit OR a bit de los dos 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. No es posible realizar desbordamientos en estas operaciones.No overflows are possible from these operations.
Operadores lógicos de enumeraciónEnumeration logical operators
Cada tipo de enumeración E proporciona implícitamente los siguientes 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);
El resultado de evaluar x op y , donde x y y son expresiones de un tipo de enumeración E con un tipo subyacente U , y op es uno de los operadores lógicos, es exactamente igual que evaluar (E)((U)x op (U)y) .The result of evaluating x op y, where x and y are expressions of an enumeration type E with an underlying type U, and op is one of the logical operators, is exactly the same as evaluating (E)((U)x op (U)y). En otras palabras, los operadores lógicos de tipo de enumeración simplemente realizan la operación lógica en el tipo subyacente de los dos 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 booleanosBoolean logical operators
Los operadores lógicos booleanos predefinidos son:The predefined boolean logical operators are:
bool operator &(bool x, bool y);
bool operator |(bool x, bool y);
bool operator ^(bool x, bool y);
El resultado de x & y es true si tanto x como y son true.The result of x & y is true if both x and y are true. De lo contrario, el resultado es false.Otherwise, the result is false.
El resultado de x | y es true si x o y es true .The result of x | y is true if either x or y is true. De lo contrario, el resultado es false.Otherwise, the result is false.
El resultado de x ^ y es true si x es true y y es false , o x es false y y es true .The result of x ^ y is true if x is true and y is false, or x is false and y is true. De lo contrario, el resultado es false.Otherwise, the result is false. Cuando los operandos son de tipo bool , el ^ operador calcula el mismo resultado que el != operador.When the operands are of type bool, the ^ operator computes the same result as the != operator.
Operadores lógicos booleanos que aceptan valores NULLNullable boolean logical operators
El tipo Boolean que acepta valores NULL bool? puede representar tres valores,, true false y null , y es conceptualmente similar al tipo de tres valores que se usa para las Expresiones booleanas en 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 asegurarse de que los resultados generados por los & | operadores y para los bool? operandos son coherentes con la lógica de tres valores de SQL, se proporcionan los siguientes operadores predefinidos: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);
En la tabla siguiente se enumeran los resultados generados por estos operadores para todas las combinaciones de los valores true , false y 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 condicionalesConditional logical operators
Los operadores && y || se denominan operadores lógicos condicionales.The && and || operators are called the conditional logical operators. También se denominan operadores lógicos "de cortocircuito".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
;
Los && || operadores y son versiones condicionales de & los | operadores y:The && and || operators are conditional versions of the & and | operators:
- La operación
x && ycorresponde a la operaciónx & y, salvo queysolo se evalúa sixno esfalse.The operationx && ycorresponds to the operationx & y, except thatyis evaluated only ifxis notfalse. - La operación
x || ycorresponde a la operaciónx | y, salvo queysolo se evalúa sixno estrue.The operationx || ycorresponds to the operationx | y, except thatyis evaluated only ifxis nottrue.
Si un operando de un operador lógico condicional tiene el tipo en tiempo de compilación dynamic , la expresión está enlazada dinámicamente (enlace dinámico).If an operand of a conditional logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). En este caso, el tipo en tiempo de compilación de la expresión es dynamic y la resolución que se describe a continuación se realiza en tiempo de ejecución mediante el tipo en tiempo de ejecución de los operandos que tienen el tipo en tiempo de compilación 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.
Una operación con el formato x && y o x || y se procesa aplicando la resolución de sobrecarga (resolución de sobrecarga del operador binario) como si la operación se hubiera escrito x & y o 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. A continuación,Then,
- Si la resolución de sobrecarga no encuentra un único operador mejor, o si la resolución de sobrecarga selecciona uno de los operadores lógicos de enteros predefinidos, se produce un error en tiempo de enlace.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.
- De lo contrario, si el operador seleccionado es uno de los operadores lógicos booleanos predefinidos (operadores lógicos booleanos) o los operadores lógicos booleanos que aceptan valores NULL (operadores lógicosbooleanos que aceptan valores NULL), la operación se procesa como se describe en operadores lógicos condicionales booleanos.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.
- De lo contrario, el operador seleccionado es un operador definido por el usuario y la operación se procesa como se describe en operadores lógicos condicionales definidos por el usuario.Otherwise, the selected operator is a user-defined operator, and the operation is processed as described in User-defined conditional logical operators.
No es posible sobrecargar directamente los operadores lógicos condicionales.It is not possible to directly overload the conditional logical operators. Sin embargo, dado que los operadores lógicos condicionales se evalúan en términos de los operadores lógicos normales, las sobrecargas de los operadores lógicos normales son, con ciertas restricciones, que también se consideran sobrecargas de los operadores lógicos condicionales.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. Esto se describe con más detalle en operadores lógicos condicionales definidos por el usuario.This is described further in User-defined conditional logical operators.
Operadores lógicos condicionales booleanosBoolean conditional logical operators
Cuando los operandos de && o || son de tipo bool , o cuando los operandos son de tipos que no definen un aplicable operator & o operator | , pero definen conversiones implícitas en bool , la operación se procesa de la siguiente manera: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:
- La operación
x && yse evalúa comox ? y : false.The operationx && yis evaluated asx ? y : false. En otras palabras,xse evalúa primero y se convierte al tipobool.In other words,xis first evaluated and converted to typebool. Después, sixestrue,yse evalúa y se convierte al tipobool, y se convierte en el resultado de la operación.Then, ifxistrue,yis evaluated and converted to typebool, and this becomes the result of the operation. De lo contrario, el resultado de la operación esfalse.Otherwise, the result of the operation isfalse. - La operación
x || yse evalúa comox ? true : y.The operationx || yis evaluated asx ? true : y. En otras palabras,xse evalúa primero y se convierte al tipobool.In other words,xis first evaluated and converted to typebool. Después, sixestrue, el resultado de la operación estrue.Then, ifxistrue, the result of the operation istrue. De lo contrario,yse evalúa y se convierte al tipobool, y se convierte en el resultado de la operación.Otherwise,yis evaluated and converted to typebool, and this becomes the result of the operation.
Operadores lógicos condicionales definidos por el usuarioUser-defined conditional logical operators
Cuando los operandos de && o || son de tipos que declaran un o definido por operator & el usuario aplicable, deben cumplirse operator | las dos condiciones siguientes, donde T es el tipo en el que se declara el operador seleccionado: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:
- El tipo de valor devuelto y el tipo de cada parámetro del operador seleccionado deben ser
T.The return type and the type of each parameter of the selected operator must beT. En otras palabras, el operador debe calcular la lógicaANDor lógicaORde dos operandos de tipoTy debe devolver un resultado de tipoT.In other words, the operator must compute the logicalANDor the logicalORof two operands of typeT, and must return a result of typeT. Tdebe contener declaraciones deoperator trueyoperator false.Tmust contain declarations ofoperator trueandoperator false.
Se produce un error en tiempo de enlace si no se cumple alguno de estos requisitos.A binding-time error occurs if either of these requirements is not satisfied. De lo contrario, la && || operación OR se evalúa combinando el definido por el usuario operator true o operator false con el operador definido por el usuario seleccionado:Otherwise, the && or || operation is evaluated by combining the user-defined operator true or operator false with the selected user-defined operator:
- La operación
x && yse evalúa comoT.false(x) ? x : T.&(x, y), dondeT.false(x)es una invocación deloperator falsedeclarado enT, yT.&(x, y)es una invocación del seleccionadooperator &.The operationx && yis evaluated asT.false(x) ? x : T.&(x, y), whereT.false(x)is an invocation of theoperator falsedeclared inT, andT.&(x, y)is an invocation of the selectedoperator &. En otras palabras,xse evalúa primero yoperator falsese invoca en el resultado para determinar sixes false definitivamente.In other words,xis first evaluated andoperator falseis invoked on the result to determine ifxis definitely false. Después, sixes definitivamente false, el resultado de la operación es el valor previamente calculado parax.Then, ifxis definitely false, the result of the operation is the value previously computed forx. De lo contrario,yse evalúa y el seleccionadooperator &se invoca en el valor calculado previamente paraxy el valor calculado paraypara generar el resultado de la operación.Otherwise,yis evaluated, and the selectedoperator &is invoked on the value previously computed forxand the value computed foryto produce the result of the operation. - La operación
x || yse evalúa comoT.true(x) ? x : T.|(x, y), dondeT.true(x)es una invocación deloperator truedeclarado enT, yT.|(x,y)es una invocación del seleccionadooperator|.The operationx || yis evaluated asT.true(x) ? x : T.|(x, y), whereT.true(x)is an invocation of theoperator truedeclared inT, andT.|(x,y)is an invocation of the selectedoperator|. En otras palabras,xse evalúa primero yoperator truese invoca en el resultado para determinar sixes true definitivamente.In other words,xis first evaluated andoperator trueis invoked on the result to determine ifxis definitely true. A continuación, sixes true definitivamente, el resultado de la operación es el valor previamente calculado parax.Then, ifxis definitely true, the result of the operation is the value previously computed forx. De lo contrario,yse evalúa y el seleccionadooperator |se invoca en el valor calculado previamente paraxy el valor calculado paraypara generar el resultado de la operación.Otherwise,yis evaluated, and the selectedoperator |is invoked on the value previously computed forxand the value computed foryto produce the result of the operation.
En cualquiera de estas operaciones, la expresión proporcionada por x solo se evalúa una vez, y la expresión proporcionada por y no se evalúa ni se evalúa exactamente una 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 obtener un ejemplo de un tipo que implementa operator true y operator false , vea Database Boolean Type.For an example of a type that implements operator true and operator false, see Database boolean type.
Operador de uso combinado de NULLThe null coalescing operator
El ?? operador se denomina operador de uso combinado de NULL.The ?? operator is called the null coalescing operator.
null_coalescing_expression
: conditional_or_expression
| conditional_or_expression '??' null_coalescing_expression
;
Una expresión de fusión nula del formulario a ?? b requiere a que sea de un tipo que acepte valores NULL o un tipo de referencia.A null coalescing expression of the form a ?? b requires a to be of a nullable type or reference type. Si a no es null, el resultado de a ?? b es a ; de lo contrario, el resultado es b .If a is non-null, the result of a ?? b is a; otherwise, the result is b. La operación b solo se evalúa si a es NULL.The operation evaluates b only if a is null.
El operador de uso combinado de NULL es asociativo a la derecha, lo que significa que las operaciones se agrupan de derecha a izquierda.The null coalescing operator is right-associative, meaning that operations are grouped from right to left. Por ejemplo, una expresión con el formato a ?? b ?? c se evalúa como a ?? (b ?? c) .For example, an expression of the form a ?? b ?? c is evaluated as a ?? (b ?? c). En términos generales, una expresión con el formato E1 ?? E2 ?? ... ?? En devuelve el primero de los operandos que no son NULL, o null si todos los operandos son NULL.In general terms, an expression of the form E1 ?? E2 ?? ... ?? En returns the first of the operands that is non-null, or null if all operands are null.
El tipo de la expresión a ?? b depende de las conversiones implícitas que están disponibles en los operandos.The type of the expression a ?? b depends on which implicit conversions are available on the operands. En orden de preferencia, el tipo de a ?? b es A0 , A o B , donde A es el tipo de a (siempre que a tenga un tipo), B es el tipo de b (siempre que b tenga un tipo) y A0 es el tipo subyacente de A si A es un tipo que acepta valores NULL, o de A lo contrario.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. En concreto, a ?? b se procesa de la siguiente manera:Specifically, a ?? b is processed as follows:
- Si
Aexiste y no es un tipo que acepta valores NULL o un tipo de referencia, se produce un error en tiempo de compilación.IfAexists and is not a nullable type or a reference type, a compile-time error occurs. - Si
bes una expresión dinámica, el tipo de resultado esdynamic.Ifbis a dynamic expression, the result type isdynamic. En tiempo de ejecución,ase evalúa primero.At run-time,ais first evaluated. Siano es null,ase convierte en dinámico y se convierte en el resultado.Ifais not null,ais converted to dynamic, and this becomes the result. De lo contrario,bse evalúa y se convierte en el resultado.Otherwise,bis evaluated, and this becomes the result. - De lo contrario, si
Aexiste y es un tipo que acepta valores NULL y existe una conversión implícita debaA0, el tipo de resultado esA0.Otherwise, ifAexists and is a nullable type and an implicit conversion exists frombtoA0, the result type isA0. En tiempo de ejecución,ase evalúa primero.At run-time,ais first evaluated. Siano es null,ase desencapsulará enA0el tipo y se convertirá en el resultado.Ifais not null,ais unwrapped to typeA0, and this becomes the result. De lo contrario,bse evalúa y se convierte al tipoA0, y se convierte en el resultado.Otherwise,bis evaluated and converted to typeA0, and this becomes the result. - De lo contrario, si
Aexiste y existe una conversión implícita debaA, el tipo de resultado esA.Otherwise, ifAexists and an implicit conversion exists frombtoA, the result type isA. En tiempo de ejecución,ase evalúa primero.At run-time,ais first evaluated. Siano es null,ase convierte en el resultado.Ifais not null,abecomes the result. De lo contrario,bse evalúa y se convierte al tipoA, y se convierte en el resultado.Otherwise,bis evaluated and converted to typeA, and this becomes the result. - De lo contrario, si
btiene un tipoBy existe una conversión implícita deaaB, el tipo de resultado esB.Otherwise, ifbhas a typeBand an implicit conversion exists fromatoB, the result type isB. En tiempo de ejecución,ase evalúa primero.At run-time,ais first evaluated. Siano es null,ase desencapsulará enA0el tipo (siAexiste y acepta valores NULL) y se convertirá al tipo, lo que seBconvierte en el resultado.Ifais not null,ais unwrapped to typeA0(ifAexists and is nullable) and converted to typeB, and this becomes the result. De lo contrario,bse evalúa y se convierte en el resultado.Otherwise,bis evaluated and becomes the result. - De lo contrario,
aybson incompatibles y se produce un error en tiempo de compilación.Otherwise,aandbare incompatible, and a compile-time error occurs.
Operador condicionalConditional operator
El ?: operador se denomina operador condicional.The ?: operator is called the conditional operator. En ocasiones también se denomina operador ternario.It is at times also called the ternary operator.
conditional_expression
: null_coalescing_expression
| null_coalescing_expression '?' expression ':' expression
;
Una expresión condicional del formulario b ? x : y evalúa primero la condición b .A conditional expression of the form b ? x : y first evaluates the condition b. Después, si b es true , x se evalúa y se convierte en el resultado de la operación.Then, if b is true, x is evaluated and becomes the result of the operation. De lo contrario, y se evalúa y se convierte en el resultado de la operación.Otherwise, y is evaluated and becomes the result of the operation. Una expresión condicional nunca evalúa x y y .A conditional expression never evaluates both x and y.
El operador condicional es asociativo a la derecha, lo que significa que las operaciones se agrupan de derecha a izquierda.The conditional operator is right-associative, meaning that operations are grouped from right to left. Por ejemplo, una expresión con el formato a ? b : c ? d : e se evalúa 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).
El primer operando del ?: operador debe ser una expresión que se pueda convertir implícitamente a bool , o una expresión de un tipo que implemente operator true .The first operand of the ?: operator must be an expression that can be implicitly converted to bool, or an expression of a type that implements operator true. Si no se cumple ninguno de estos requisitos, se produce un error en tiempo de compilación.If neither of these requirements is satisfied, a compile-time error occurs.
Los operandos segundo y tercero, x y y , del ?: operador controlan el tipo de la expresión condicional.The second and third operands, x and y, of the ?: operator control the type of the conditional expression.
- Si
xtiene el tipoXyytiene el tipoY, entoncesIfxhas typeXandyhas typeYthen- Si existe una conversión implícita (conversiones implícitas) de
XaY, pero no deYaX, entoncesYes el tipo de la expresión condicional.If an implicit conversion (Implicit conversions) exists fromXtoY, but not fromYtoX, thenYis the type of the conditional expression. - Si existe una conversión implícita (conversiones implícitas) de
YaX, pero no deXaY, entoncesXes el tipo de la expresión condicional.If an implicit conversion (Implicit conversions) exists fromYtoX, but not fromXtoY, thenXis the type of the conditional expression. - De lo contrario, no se puede determinar ningún tipo de expresión y se produce un error en tiempo de compilación.Otherwise, no expression type can be determined, and a compile-time error occurs.
- Si existe una conversión implícita (conversiones implícitas) de
- Si solo uno de
xyytiene un tipo, yxyy, de se pueden convertir implícitamente a ese tipo, es el tipo de la expresión condicional.If only one ofxandyhas a type, and bothxandy, of are implicitly convertible to that type, then that is the type of the conditional expression. - De lo contrario, no se puede determinar ningún tipo de expresión y se produce un error en tiempo de compilación.Otherwise, no expression type can be determined, and a compile-time error occurs.
El procesamiento en tiempo de ejecución de una expresión condicional con el formato b ? x : y consta de los siguientes pasos:The run-time processing of a conditional expression of the form b ? x : y consists of the following steps:
- En primer lugar,
bse evalúa yboolse determina el valor deb:First,bis evaluated, and theboolvalue ofbis determined:- Si una conversión implícita del tipo de
bboolexiste, esta conversión implícita se realiza para generar unboolvalor.If an implicit conversion from the type ofbtoboolexists, then this implicit conversion is performed to produce aboolvalue. - De lo contrario, el
operator truedefinido por el tipo debse invoca para generar unboolvalor.Otherwise, theoperator truedefined by the type ofbis invoked to produce aboolvalue.
- Si una conversión implícita del tipo de
- Si el
boolvalor generado por el paso anterior estrue,xse evalúa y se convierte al tipo de la expresión condicional y se convierte en el resultado de la expresión condicional.If theboolvalue produced by the step above istrue, thenxis evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression. - De lo contrario,
yse evalúa y se convierte al tipo de la expresión condicional y se convierte en el resultado de la expresión condicional.Otherwise,yis evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.
Expresiones de funciones anónimasAnonymous function expressions
Una función anónima es una expresión que representa una definición de método "en línea".An anonymous function is an expression that represents an "in-line" method definition. Una función anónima no tiene un valor o un tipo en y de sí mismo, pero se pueden convertir en un tipo de árbol de expresión o delegado compatible.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. La evaluación de una conversión de función anónima depende del tipo de destino de la conversión: si es un tipo de delegado, la conversión se evalúa como un valor de delegado que hace referencia al método que define la función anónima.The evaluation of an anonymous function conversion depends on the target type of the conversion: If it is a delegate type, the conversion evaluates to a delegate value referencing the method which the anonymous function defines. Si es un tipo de árbol de expresión, la conversión se evalúa como un árbol de expresión que representa la estructura del método como una estructura 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, hay dos tipos sintácticos de funciones anónimas, es decir, lambda_expression s y 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 casi todos los propósitos, lambda_expression s son más concisos y expresivos que anonymous_method_expression s, que permanecen en el lenguaje por compatibilidad con versiones 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
;
El => operador tiene la misma prioridad que la asignación ( = ) y es asociativo a la derecha.The => operator has the same precedence as assignment (=) and is right-associative.
Una función anónima con el async modificador es una función asincrónica y sigue las reglas descritas en funciones asincrónicas.An anonymous function with the async modifier is an async function and follows the rules described in Async functions.
Los parámetros de una función anónima en forma de lambda_expression se pueden escribir explícita o implícitamente.The parameters of an anonymous function in the form of a lambda_expression can be explicitly or implicitly typed. En una lista de parámetros con tipo explícito, se indica explícitamente el tipo de cada parámetro.In an explicitly typed parameter list, the type of each parameter is explicitly stated. En una lista de parámetros con tipos implícitos, los tipos de los parámetros se deducen del contexto en el que se produce la función anónima; en concreto, cuando la función anónima se convierte en un tipo de delegado o un tipo de árbol de expresión compatible, ese tipo proporciona los tipos de parámetro (conversiones de funciones anónimas).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).
En una función anónima con un solo parámetro con tipo implícito, los paréntesis se pueden omitir en la lista de parámetros.In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. En otras palabras, una función anónima con el formatoIn other words, an anonymous function of the form
( param ) => expr
se puede abreviar comocan be abbreviated to
param => expr
La lista de parámetros de una función anónima en forma de un anonymous_method_expression es opcional.The parameter list of an anonymous function in the form of an anonymous_method_expression is optional. Si se especifica, los parámetros se deben escribir explícitamente.If given, the parameters must be explicitly typed. En caso contrario, la función anónima se convertirá en un delegado con cualquier lista de parámetros que no contenga out parámetros.If not, the anonymous function is convertible to a delegate with any parameter list not containing out parameters.
Se puede tener acceso al cuerpo de un bloque de una función anónima (puntos de conexión y disponibilidad) a menos que la función anónima se encuentre dentro de una instrucción inalcanzable.A block body of an anonymous function is reachable (End points and reachability) unless the anonymous function occurs inside an unreachable statement.
A continuación se muestran algunos ejemplos de funciones 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
El comportamiento de lambda_expression s y anonymous_method_expression s es el mismo, salvo los siguientes puntos:The behavior of lambda_expression s and anonymous_method_expression s is the same except for the following points:
- anonymous_method_expression s permiten omitir completamente la lista de parámetros, lo que produce Convertibility para delegar tipos de cualquier 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 permiten omitir e inferir los tipos de parámetro, mientras que anonymous_method_expression s requieren que se indiquen explícitamente los tipos de parámetro.lambda_expression s permit parameter types to be omitted and inferred whereas anonymous_method_expression s require parameter types to be explicitly stated.
- El cuerpo de una lambda_expression puede ser una expresión o un bloque de instrucciones, mientras que el cuerpo de una anonymous_method_expression debe ser un bloque de instrucciones.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.
- Solo lambda_expression s tienen conversiones a tipos de árbol de expresión compatibles (tipos de árbol de expresión).Only lambda_expression s have conversions to compatible expression tree types (Expression tree types).
Firmas de funciones anónimasAnonymous function signatures
El anonymous_function_signature opcional de una función anónima define los nombres y, opcionalmente, los tipos de los parámetros formales de la función 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. El ámbito de los parámetros de la función anónima es el anonymous_function_body.The scope of the parameters of the anonymous function is the anonymous_function_body. (Ámbitos) Junto con la lista de parámetros (si se especifica), el cuerpo del método anónimo constituye un espacio de declaración (declaraciones).(Scopes) Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space (Declarations). Por lo tanto, es un error en tiempo de compilación que el nombre de un parámetro de la función anónima coincida con el nombre de una variable local, una constante local o un parámetro cuyo ámbito incluya el anonymous_method_expression o lambda_expression.It is thus a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant or parameter whose scope includes the anonymous_method_expression or lambda_expression.
Si una función anónima tiene un explicit_anonymous_function_signature, el conjunto de tipos de delegado compatibles y los tipos de árbol de expresión están restringidos a los que tienen los mismos tipos de parámetros y modificadores en el mismo orden.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. A diferencia de las conversiones de grupos de métodos (conversiones de grupos de métodos), no se admite la varianza de tipos de parámetros de función anónimos.In contrast to method group conversions (Method group conversions), contra-variance of anonymous function parameter types is not supported. Si una función anónima no tiene un anonymous_function_signature, el conjunto de tipos de delegado compatibles y tipos de árbol de expresión está restringido a los que no tienen 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.
Tenga en cuenta que un anonymous_function_signature no puede incluir atributos o una matriz de parámetros.Note that an anonymous_function_signature cannot include attributes or a parameter array. No obstante, un anonymous_function_signature puede ser compatible con un tipo de delegado cuya lista de parámetros contiene una matriz de parámetros.Nevertheless, an anonymous_function_signature may be compatible with a delegate type whose parameter list contains a parameter array.
Tenga en cuenta también que la conversión a un tipo de árbol de expresión, incluso si es compatible, todavía puede producir un error en tiempo de compilación (tipos de árbol de expresión).Note also that conversion to an expression tree type, even if compatible, may still fail at compile-time (Expression tree types).
Cuerpos de función anónimosAnonymous function bodies
El cuerpo (expresión o bloque) de una función anónima está sujeto a las siguientes reglas:The body (expression or block) of an anonymous function is subject to the following rules:
- Si la función anónima incluye una firma, los parámetros especificados en la firma están disponibles en el cuerpo.If the anonymous function includes a signature, the parameters specified in the signature are available in the body. Si la función anónima no tiene ninguna firma, se puede convertir en un tipo de delegado o tipo de expresión con parámetros (conversiones de funciones anónimas), pero no se puede tener acceso a los parámetros en el cuerpo.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.
- A excepción de los
refoutparámetros o especificados en la firma (si existen) de la función anónima envolvente más cercana, se trata de un error en tiempo de compilación para que el cuerpo tenga acceso a unrefoutparámetro o.Except forreforoutparameters specified in the signature (if any) of the nearest enclosing anonymous function, it is a compile-time error for the body to access areforoutparameter. - Cuando el tipo de
thises un tipo de estructura, es un error en tiempo de compilación para que el cuerpo tenga accesothis.When the type ofthisis a struct type, it is a compile-time error for the body to accessthis. Esto es así si el acceso es explícito (como enthis.x) o implícito (como enxdondexes un miembro de instancia de la estructura).This is true whether the access is explicit (as inthis.x) or implicit (as inxwherexis an instance member of the struct). Esta regla simplemente prohíbe el acceso y no afecta a si la búsqueda de miembros da como resultado un miembro de la estructura.This rule simply prohibits such access and does not affect whether member lookup results in a member of the struct. - El cuerpo tiene acceso a las variables externas (variables externas) de la función anónima.The body has access to the outer variables (Outer variables) of the anonymous function. El acceso de una variable externa hará referencia a la instancia de la variable que está activa en el momento en que se evalúa el lambda_expression o anonymous_method_expression (evaluación de expresiones de función 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).
- Es un error en tiempo de compilación que el cuerpo contenga una instrucción
goto, unabreakinstrucción o unacontinueinstrucción cuyo destino esté fuera del cuerpo o dentro del cuerpo de una función anónima contenida.It is a compile-time error for the body to contain agotostatement,breakstatement, orcontinuestatement whose target is outside the body or within the body of a contained anonymous function. - Una
returninstrucción del cuerpo devuelve el control de una invocación de la función anónima envolvente más cercana, no del miembro de función envolvente.Areturnstatement in the body returns control from an invocation of the nearest enclosing anonymous function, not from the enclosing function member. Una expresión especificada en unareturninstrucción se debe poder convertir implícitamente al tipo de valor devuelto del tipo de delegado o del tipo de árbol de expresión al que se convierte el lambda_expression o anonymous_method_expression más próximo (conversiones de función anónima).An expression specified in areturnstatement 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).
No se especifica explícitamente si hay alguna manera de ejecutar el bloque de una función anónima que no sea a través de la evaluación y la invocación del lambda_expression o anonymous_method_expression.It is explicitly unspecified whether there is any way to execute the block of an anonymous function other than through evaluation and invocation of the lambda_expression or anonymous_method_expression. En concreto, el compilador puede optar por implementar una función anónima mediante la sintetización de uno o varios métodos o tipos con nombre.In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types. Los nombres de estos elementos sintetizados deben tener un formato reservado para el uso del compilador.The names of any such synthesized elements must be of a form reserved for compiler use.
Resolución de sobrecarga y funciones anónimasOverload resolution and anonymous functions
Las funciones anónimas de una lista de argumentos participan en la inferencia de tipos y en la resolución de sobrecarga.Anonymous functions in an argument list participate in type inference and overload resolution. Consulte la inferencia de tipos y la resolución de sobrecargas para ver las reglas exactas.Please refer to Type inference and Overload resolution for the exact rules.
En el ejemplo siguiente se muestra el efecto de las funciones anónimas en la resolución 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;
}
}
La ItemList<T> clase tiene dos Sum métodos.The ItemList<T> class has two Sum methods. Cada toma un selector argumento, que extrae el valor que se va a sumar de un elemento de lista.Each takes a selector argument, which extracts the value to sum over from a list item. El valor extraído puede ser int o, double y la suma resultante también es int o double .The extracted value can be either an int or a double and the resulting sum is likewise either an int or a double.
Los Sum métodos se pueden utilizar, por ejemplo, para calcular las sumas de una lista de líneas de detalle en un pedido.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);
...
}
En la primera invocación de orderDetails.Sum , ambos Sum métodos son aplicables porque la función anónima d => d. UnitCount es compatible con Func<Detail,int> y 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>. Sin embargo, la resolución de sobrecarga selecciona el primer Sum método porque la conversión a Func<Detail,int> es mejor que la conversión a 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>.
En la segunda invocación de orderDetails.Sum , solo el segundo Sum método es aplicable porque la función anónima d => d.UnitPrice * d.UnitCount genera un valor de 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. Por lo tanto, la resolución de sobrecarga elige el segundo Sum método para esa invocación.Thus, overload resolution picks the second Sum method for that invocation.
Funciones anónimas y enlace dinámicoAnonymous functions and dynamic binding
Una función anónima no puede ser un receptor, un argumento o un operando de una operación enlazada dinámicamente.An anonymous function cannot be a receiver, argument or operand of a dynamically bound operation.
Variables externasOuter variables
Cualquier variable local, parámetro de valor o matriz de parámetros cuyo ámbito incluya el lambda_expression o anonymous_method_expression se denomina una variable externa de la función 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. En un miembro de función de instancia de una clase, el this valor se considera un parámetro de valor y es una variable externa de cualquier función anónima incluida dentro del miembro de función.In an instance function member of a class, the this value is considered a value parameter and is an outer variable of any anonymous function contained within the function member.
Variables externas capturadasCaptured outer variables
Cuando una función anónima hace referencia a una variable externa, se dice que la función anónima ha capturado la variable externa.When an outer variable is referenced by an anonymous function, the outer variable is said to have been captured by the anonymous function. Normalmente, la duración de una variable local se limita a la ejecución del bloque o la instrucción con la que está asociada (variables locales).Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated (Local variables). Sin embargo, la duración de una variable externa capturada se extiende al menos hasta que el delegado o el árbol de expresión creado a partir de la función anónima sea válido para la recolección de elementos no utilizados.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.
En el ejemploIn the example
using System;
delegate int D();
class Test
{
static D F() {
int x = 0;
D result = () => ++x;
return result;
}
static void Main() {
D d = F();
Console.WriteLine(d());
Console.WriteLine(d());
Console.WriteLine(d());
}
}
la x función anónima captura la variable local y la duración de x se extiende al menos hasta que el delegado devuelto F por se pueda seleccionar para la recolección de elementos no utilizados (que no se produce hasta el final del 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). Dado que cada invocación de la función anónima funciona en la misma instancia de x , el resultado del ejemplo es:Since each invocation of the anonymous function operates on the same instance of x, the output of the example is:
1
2
3
Cuando una función anónima captura una variable local o un parámetro de valor, la variable local o el parámetro ya no se considera una variable fija (variables fijas y móviles), sino que se considera una variable móvil.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. Por lo tanto, cualquier unsafe código que toma la dirección de una variable externa capturada debe usar primero la fixed instrucción para corregir la variable.Thus any unsafe code that takes the address of a captured outer variable must first use the fixed statement to fix the variable.
Tenga en cuenta que, a diferencia de una variable no capturada, una variable local capturada se puede exponer simultáneamente a varios subprocesos de ejecución.Note that unlike an uncaptured variable, a captured local variable can be simultaneously exposed to multiple threads of execution.
Creación de instancias de variables localesInstantiation of local variables
Se considera que se crea una instancia de una variable local cuando la ejecución entra en el ámbito de la variable.A local variable is considered to be instantiated when execution enters the scope of the variable. Por ejemplo, cuando se invoca el método siguiente, x se crea una instancia de la variable local y se inicializa tres veces, una vez para cada iteración del bucle.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;
...
}
}
Sin embargo, mover la declaración de x fuera del bucle produce una única creación de instancias 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;
...
}
}
Cuando no se capturan, no hay forma de observar exactamente la frecuencia con la que se crea una instancia de una variable local, ya que las duraciones de las instancias no se pueden usar para que cada creación de instancias use simplemente la misma ubicación de almacenamiento.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. Sin embargo, cuando una función anónima captura una variable local, los efectos de la creación de instancias se hacen evidentes.However, when an anonymous function captures a local variable, the effects of instantiation become apparent.
En el ejemploThe 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();
}
}
genera el resultado:produces the output:
1
3
5
Sin embargo, cuando la declaración de x se mueve fuera del bucle: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;
}
el resultado es:the output is:
5
5
5
Si un bucle for declara una variable de iteración, se considera que esa variable se declara fuera del bucle.If a for-loop declares an iteration variable, that variable itself is considered to be declared outside of the loop. Por lo tanto, si se cambia el ejemplo para capturar la variable de iteración en sí: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;
}
solo se captura una instancia de la variable de iteración, que genera el resultado:only one instance of the iteration variable is captured, which produces the output:
3
3
3
Es posible que los delegados de función anónimos compartan algunas variables capturadas pero tengan instancias independientes de otras.It is possible for anonymous function delegates to share some captured variables yet have separate instances of others. Por ejemplo, si F se cambia aFor 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;
}
los tres delegados capturan la misma instancia de x , pero las instancias independientes de y , y el resultado es:the three delegates capture the same instance of x but separate instances of y, and the output is:
1 1
2 1
3 1
Las funciones anónimas independientes pueden capturar la misma instancia de una variable externa.Separate anonymous functions can capture the same instance of an outer variable. En el ejemplo: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());
}
}
las dos funciones anónimas capturan la misma instancia de la variable local x y, por tanto, pueden "comunicarse" a través de esa variable.the two anonymous functions capture the same instance of the local variable x, and they can thus "communicate" through that variable. La salida del ejemplo es:The output of the example is:
5
10
Evaluación de expresiones de función anónimasEvaluation of anonymous function expressions
Una función anónima F siempre debe convertirse en un tipo de delegado D o en un tipo E de árbol de expresión, ya sea directamente o a través de la ejecución de una expresión de creación 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). Esta conversión determina el resultado de la función anónima, como se describe en conversiones de funciones anónimas.This conversion determines the result of the anonymous function, as described in Anonymous function conversions.
Expresiones de consultaQuery expressions
Las expresiones de consulta proporcionan una sintaxis integrada de lenguaje para las consultas que es similar a los lenguajes de consulta jerárquica y relacional, como SQL y 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
;
Una expresión de consulta comienza con una from cláusula y termina con una select group cláusula o.A query expression begins with a from clause and ends with either a select or group clause. La from cláusula Initial puede ir seguida de cero o más from let cláusulas,, where join o orderby .The initial from clause can be followed by zero or more from, let, where, join or orderby clauses. Cada from cláusula es un generador que introduce una *variable de rango _ que va por los elementos de una secuencia _ * * *.Each from clause is a generator introducing a range variable _ which ranges over the elements of a _sequence**. Cada let cláusula presenta una variable de rango que representa un valor calculado por medio de las variables de rango anteriores.Each let clause introduces a range variable representing a value computed by means of previous range variables. Cada where cláusula es un filtro que excluye elementos del resultado.Each where clause is a filter that excludes items from the result. Cada join cláusula compara las claves especificadas de la secuencia de origen con claves de otra secuencia, produciendo pares coincidentes.Each join clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. Cada orderby cláusula reordena los elementos según los criterios especificados. La select cláusula final o group especifica la forma del resultado en términos de las variables de rango.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 último, into se puede usar una cláusula para "Insertar" consultas tratando los resultados de una consulta como un generador en una consulta posterior.Finally, an into clause can be used to "splice" queries by treating the results of one query as a generator in a subsequent query.
Ambigüedades en expresiones de consultaAmbiguities in query expressions
Las expresiones de consulta contienen una serie de "palabras clave contextuales", es decir, identificadores que tienen un significado especial en un contexto determinado.Query expressions contain a number of "contextual keywords", i.e., identifiers that have special meaning in a given context. En concreto, se trata from de,, where join , on , equals , into , let , orderby , ascending ,, descending select group y by .Specifically these are from, where, join, on, equals, into, let, orderby, ascending, descending, select, group and by. Para evitar ambigüedades en las expresiones de consulta producidas por el uso mixto de estos identificadores como palabras clave o nombres simples, estos identificadores se consideran palabras clave cuando se producen en cualquier parte de una expresión 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 este propósito, una expresión de consulta es cualquier expresión que empiece por " from identifier " seguido de cualquier token excepto " ; ", " = " o " , ".For this purpose, a query expression is any expression that starts with "from identifier" followed by any token except ";", "=" or ",".
Para usar estas palabras como identificadores dentro de una expresión de consulta, se les puede anteponer " @ " (identificadores).In order to use these words as identifiers within a query expression, they can be prefixed with "@" (Identifiers).
Traducción de expresiones de consultaQuery expression translation
El lenguaje C# no especifica la semántica de ejecución de las expresiones de consulta.The C# language does not specify the execution semantics of query expressions. En su lugar, las expresiones de consulta se convierten en invocaciones de métodos que se adhieren al patrón de expresión de consulta (el patrón de expresión de consulta).Rather, query expressions are translated into invocations of methods that adhere to the query expression pattern (The query expression pattern). En concreto, las expresiones de consulta se convierten en invocaciones de métodos denominados Where ,, Select SelectMany , Join , GroupJoin , OrderBy , OrderByDescending , ThenBy , ThenByDescending , GroupBy y Cast . Se espera que estos métodos tengan firmas concretas y tipos de resultado, como se describe en el patrón de expresión 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. Estos métodos pueden ser métodos de instancia del objeto que se consulta o métodos de extensión que son externos al objeto e implementan la ejecución real de la 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.
La conversión de las expresiones de consulta a las invocaciones de método es una asignación sintáctica que se produce antes de que se haya realizado cualquier enlace de tipo o resolución de sobrecarga.The translation from query expressions to method invocations is a syntactic mapping that occurs before any type binding or overload resolution has been performed. Se garantiza que la conversión es sintácticamente correcta, pero no se garantiza que genere código C# correcto semánticamente.The translation is guaranteed to be syntactically correct, but it is not guaranteed to produce semantically correct C# code. Después de la traducción de las expresiones de consulta, las invocaciones de método resultantes se procesan como invocaciones de método regulares y esto puede a su vez detectar errores, por ejemplo, si los métodos no existen, si los argumentos tienen tipos incorrectos, o si los métodos son genéricos y se produce un error en la inferencia de tipos.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.
Una expresión de consulta se procesa mediante la aplicación repetida de las siguientes traducciones hasta que no se puedan realizar más reducciones.A query expression is processed by repeatedly applying the following translations until no further reductions are possible. Las traducciones se muestran por orden de aplicación: cada sección presupone que las traducciones de las secciones anteriores se han realizado de forma exhaustiva y, una vez agotadas, una sección no se volverá a visitar posteriormente en el procesamiento de la misma expresión 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.
No se permite la asignación a variables de rango en expresiones de consulta.Assignment to range variables is not allowed in query expressions. Sin embargo, se permite que una implementación de C# no siempre aplique esta restricción, ya que a veces esto no es posible con el esquema de traducción sintáctica que se muestra aquí.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.
Ciertas traducciones insertan variables de rango con identificadores transparentes indicados por * .Certain translations inject range variables with transparent identifiers denoted by *. Las propiedades especiales de los identificadores transparentes se tratan en profundidad en los identificadores transparentes.The special properties of transparent identifiers are discussed further in Transparent identifiers.
Cláusulas SELECT y GroupBy con continuacionesSelect and groupby clauses with continuations
Expresión de consulta con una continuaciónA query expression with a continuation
from ... into x ...
se traduce enis translated into
from x in ( from ... ) ...
Las traducciones de las secciones siguientes suponen que las consultas no tienen ninguna into continuación.The translations in the following sections assume that queries have no into continuations.
En el ejemploThe example
from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }
se traduce enis translated into
from g in
from c in customers
group c by c.Country
select new { Country = g.Key, CustCount = g.Count() }
la traducción final que esthe final translation of which is
customers.
GroupBy(c => c.Country).
Select(g => new { Country = g.Key, CustCount = g.Count() })
Tipos de variables de rango explícitasExplicit range variable types
Una from cláusula que especifica explícitamente un tipo de variable de rangoA from clause that explicitly specifies a range variable type
from T x in e
se traduce enis translated into
from x in ( e ) . Cast < T > ( )
Una join cláusula que especifica explícitamente un tipo de variable de rangoA join clause that explicitly specifies a range variable type
join T x in e on k1 equals k2
se traduce enis translated into
join x in ( e ) . Cast < T > ( ) on k1 equals k2
Las traducciones de las secciones siguientes suponen que las consultas no tienen tipos de variable de intervalo explícitos.The translations in the following sections assume that queries have no explicit range variable types.
En el ejemploThe example
from Customer c in customers
where c.City == "London"
select c
se traduce enis translated into
from c in customers.Cast<Customer>()
where c.City == "London"
select c
la traducción final que esthe final translation of which is
customers.
Cast<Customer>().
Where(c => c.City == "London")
Los tipos de variables de rango explícitos son útiles para consultar colecciones que implementan la interfaz no genérica IEnumerable , pero no la IEnumerable<T> interfaz 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. En el ejemplo anterior, sería el caso si customers fuera de tipo ArrayList .In the example above, this would be the case if customers were of type ArrayList.
Expresiones de consulta degeneradasDegenerate query expressions
Una expresión de consulta con el formatoA query expression of the form
from x in e select x
se traduce enis translated into
( e ) . Select ( x => x )
En el ejemploThe example
from c in customers
select c
se traduce enis translated into
customers.Select(c => c)
Una expresión de consulta degenerada es aquella que selecciona trivialmente los elementos del origen.A degenerate query expression is one that trivially selects the elements of the source. Una fase posterior de la traducción quita las consultas degeneradas que se introdujeron en otros pasos de traducción mediante su origen.A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. Sin embargo, es importante asegurarse de que el resultado de una expresión de consulta nunca sea el propio objeto de origen, ya que esto revelaría el tipo e identidad del origen al cliente de la 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. Por lo tanto, este paso protege las consultas degeneradas escritas directamente en el código fuente mediante una llamada explícita Select en el origen.Therefore this step protects degenerate queries written directly in source code by explicitly calling Select on the source. A continuación, llega a los implementadores de Select y otros operadores de consulta para asegurarse de que estos métodos nunca devuelven el propio objeto de origen.It is then up to the implementers of Select and other query operators to ensure that these methods never return the source object itself.
Cláusulas from, Let, Where, join y OrderByFrom, let, where, join and orderby clauses
Expresión de consulta con una segunda from cláusula seguida de una 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
se traduce enis translated into
( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )
Expresión de consulta con una segunda from cláusula seguida de un valor distinto de una 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
...
se traduce enis translated into
from * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } )
...
Una expresión de consulta con una let cláusulaA query expression with a let clause
from x in e
let y = f
...
se traduce enis translated into
from * in ( e ) . Select ( x => new { x , y = f } )
...
Una expresión de consulta con una where cláusulaA query expression with a where clause
from x in e
where f
...
se traduce enis translated into
from x in ( e ) . Where ( x => f )
...
Expresión de consulta con una join cláusula sin un into seguido de una 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
se traduce enis translated into
( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => v )
Expresión de consulta con una join cláusula sin un into seguido de un elemento distinto de una 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
...
se traduce enis translated into
from * in ( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })
...
Una expresión de consulta con una join cláusula con una into cláusula seguida de una 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
se traduce enis translated into
( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => v )
Una expresión de consulta con una join cláusula con un into seguido de un elemento distinto de una 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
...
se traduce enis translated into
from * in ( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => new { x1 , g })
...
Expresión de consulta con una orderby cláusulaA query expression with an orderby clause
from x in e
orderby k1 , k2 , ..., kn
...
se traduce enis translated into
from x in ( e ) .
OrderBy ( x => k1 ) .
ThenBy ( x => k2 ) .
... .
ThenBy ( x => kn )
...
Si una cláusula de ordenación especifica un descending indicador de dirección, se produce una invocación de OrderByDescending o ThenByDescending en su lugar.If an ordering clause specifies a descending direction indicator, an invocation of OrderByDescending or ThenByDescending is produced instead.
Las siguientes traducciones suponen que no let hay where join orderby cláusulas, o, ni más de una from cláusula inicial en cada expresión 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.
En el ejemploThe example
from c in customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total }
se traduce enis translated into
customers.
SelectMany(c => c.Orders,
(c,o) => new { c.Name, o.OrderID, o.Total }
)
En el ejemploThe example
from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }
se traduce enis translated into
from * in customers.
SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }
la traducción final que esthe 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 })
donde x es un identificador generado por el compilador que, de lo contrario, es invisible e inaccesible.where x is a compiler generated identifier that is otherwise invisible and inaccessible.
En el ejemploThe example
from o in orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t }
se traduce enis translated into
from * in orders.
Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) })
where t >= 1000
select new { o.OrderID, Total = t }
la traducción final que esthe 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 })
donde x es un identificador generado por el compilador que, de lo contrario, es invisible e inaccesible.where x is a compiler generated identifier that is otherwise invisible and inaccessible.
En el ejemploThe example
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }
se traduce enis translated into
customers.Join(orders, c => c.CustomerID, o => o.CustomerID,
(c, o) => new { c.Name, o.OrderDate, o.Total })
En el ejemploThe 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 }
se traduce enis translated into
from * in customers.
GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
(c, co) => new { c, co })
let n = co.Count()
where n >= 10
select new { c.Name, OrderCount = n }
la traducción final que esthe 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)
donde x y y son identificadores generados por el compilador que, de lo contrario, son invisibles e inaccesibles.where x and y are compiler generated identifiers that are otherwise invisible and inaccessible.
En el ejemploThe example
from o in orders
orderby o.Customer.Name, o.Total descending
select o
tiene la traducción finalhas the final translation
orders.
OrderBy(o => o.Customer.Name).
ThenByDescending(o => o.Total)
Cláusulas SelectSelect clauses
Una expresión de consulta con el formatoA query expression of the form
from x in e select v
se traduce enis translated into
( e ) . Select ( x => v )
excepto cuando v es el identificador x, la traducción es simplementeexcept when v is the identifier x, the translation is simply
( e )
Por ejemploFor example
from c in customers.Where(c => c.City == "London")
select c
simplemente se traduce enis simply translated into
customers.Where(c => c.City == "London")
Cláusulas GroupByGroupby clauses
Una expresión de consulta con el formatoA query expression of the form
from x in e group v by k
se traduce enis translated into
( e ) . GroupBy ( x => k , x => v )
excepto cuando v es el identificador x, la traducción esexcept when v is the identifier x, the translation is
( e ) . GroupBy ( x => k )
En el ejemploThe example
from c in customers
group c.Name by c.Country
se traduce enis translated into
customers.
GroupBy(c => c.Country, c => c.Name)
Identificadores transparentesTransparent identifiers
Ciertas traducciones insertan variables de intervalo con *identificadores transparentes _ indicados por _ .Certain translations inject range variables with *transparent identifiers _ denoted by _. Los identificadores transparentes no son una característica de lenguaje adecuada; solo existen como un paso intermedio en el proceso de conversión de expresiones de consulta.Transparent identifiers are not a proper language feature; they exist only as an intermediate step in the query expression translation process.
Cuando una traducción de consultas inserta un identificador transparente, los pasos de traducción adicionales propagan el identificador transparente en funciones 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. En esos contextos, los identificadores transparentes tienen el siguiente comportamiento:In those contexts, transparent identifiers have the following behavior:
- Cuando un identificador transparente se produce como un parámetro en una función anónima, los miembros del tipo anónimo asociado están automáticamente en el ámbito del cuerpo de la función 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.
- Cuando un miembro con un identificador transparente está en el ámbito, los miembros de ese miembro están también en el ámbito.When a member with a transparent identifier is in scope, the members of that member are in scope as well.
- Cuando un identificador transparente se produce como un declarador de miembro en un inicializador de objeto anónimo, introduce un miembro con un identificador transparente.When a transparent identifier occurs as a member declarator in an anonymous object initializer, it introduces a member with a transparent identifier.
- En los pasos de traducción descritos anteriormente, los identificadores transparentes siempre se introducen junto con los tipos anónimos, con la intención de capturar varias variables de rango como miembros de un solo 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. Una implementación de C# puede usar un mecanismo diferente que los tipos anónimos para agrupar varias variables de rango.An implementation of C# is permitted to use a different mechanism than anonymous types to group together multiple range variables. Los siguientes ejemplos de traducción suponen que se usan tipos anónimos y muestran cómo se pueden traducir los identificadores transparentes.The following translation examples assume that anonymous types are used, and show how transparent identifiers can be translated away.
En el ejemploThe example
from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.Total }
se traduce enis translated into
from * in customers.
SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.Total }
que se traduce enwhich is further translated into
customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(* => o.Total).
Select(* => new { c.Name, o.Total })
que, cuando se borran los identificadores transparentes, es 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 })
donde x es un identificador generado por el compilador que, de lo contrario, es invisible e inaccesible.where x is a compiler generated identifier that is otherwise invisible and inaccessible.
En el ejemploThe 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 }
se traduce enis translated into
from * in customers.
Join(orders, c => c.CustomerID, o => o.CustomerID,
(c, o) => new { c, o })
join d in details on o.OrderID equals d.OrderID
join p in products on d.ProductID equals p.ProductID
select new { c.Name, o.OrderDate, p.ProductName }
se reduce aún más awhich 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 })
la traducción final que esthe 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 })
donde x , y y z son identificadores generados por el compilador que, de lo contrario, son invisibles e inaccesibles.where x, y, and z are compiler generated identifiers that are otherwise invisible and inaccessible.
Patrón de expresión de consultaThe query expression pattern
El patrón de expresión de consulta establece un patrón de métodos que los tipos pueden implementar para admitir expresiones de consulta.The Query expression pattern establishes a pattern of methods that types can implement to support query expressions. Dado que las expresiones de consulta se convierten en invocaciones de método por medio de una asignación sintáctica, los tipos tienen una gran flexibilidad en cómo implementan el patrón de expresión 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 ejemplo, los métodos del patrón se pueden implementar como métodos de instancia o como métodos de extensión porque los dos tienen la misma sintaxis de invocación y los métodos pueden solicitar delegados o árboles de expresión porque las funciones anónimas son convertibles a 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 continuación se muestra la forma recomendada de un tipo genérico C<T> que admite el patrón de expresión de consulta.The recommended shape of a generic type C<T> that supports the query expression pattern is shown below. Se usa un tipo genérico para ilustrar las relaciones apropiadas entre los tipos de parámetro y de resultado, pero también es posible implementar el patrón para tipos no genéricos.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; }
}
Los métodos anteriores usan los tipos de delegado genérico Func<T1,R> y Func<T1,T2,R> , pero también podrían haber usado otros tipos de árbol de delegado o de expresión con las mismas relaciones en los tipos de parámetro y 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 la relación recomendada entre C<T> y O<T> que garantiza que los ThenBy ThenByDescending métodos y solo están disponibles en el resultado de OrderBy o 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 también la forma recomendada del resultado de GroupBy --una secuencia de secuencias, donde cada secuencia interna tiene una propiedad adicional Key .Also notice the recommended shape of the result of GroupBy -- a sequence of sequences, where each inner sequence has an additional Key property.
El System.Linq espacio de nombres proporciona una implementación del patrón de operador de consulta para cualquier tipo que implemente la System.Collections.Generic.IEnumerable<T> interfaz.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 asignaciónAssignment operators
Los operadores de asignación asignan un nuevo valor a una variable, una propiedad, un evento o un elemento de 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
;
El operando izquierdo de una asignación debe ser una expresión clasificada como una variable, un acceso de propiedad, un acceso de indexador o un acceso 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.
El = operador se denomina operador de asignación simple.The = operator is called the simple assignment operator. Asigna el valor del operando derecho a la variable, propiedad o elemento de indexador proporcionado por el operando izquierdo.It assigns the value of the right operand to the variable, property, or indexer element given by the left operand. Es posible que el operando izquierdo del operador de asignación simple no sea un acceso a eventos (excepto como se describe en eventos similares a los de campo).The left operand of the simple assignment operator may not be an event access (except as described in Field-like events). El operador de asignación simple se describe en asignación simple.The simple assignment operator is described in Simple assignment.
Los operadores de asignación distintos del = operador se denominan operadores de asignación compuesta.The assignment operators other than the = operator are called the compound assignment operators. Estos operadores realizan la operación indicada en los dos operandos y, a continuación, asignan el valor resultante a la variable, la propiedad o el elemento indexador proporcionado por el operando izquierdo.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. Los operadores de asignación compuesta se describen en asignación compuesta.The compound assignment operators are described in Compound assignment.
Los += -= operadores y con una expresión de acceso a eventos como operando izquierdo se denominan operadores de asignación de eventos.The += and -= operators with an event access expression as the left operand are called the event assignment operators. Ningún otro operador de asignación es válido con un acceso de evento como operando izquierdo.No other assignment operator is valid with an event access as the left operand. Los operadores de asignación de eventos se describen en asignación de eventos.The event assignment operators are described in Event assignment.
Los operadores de asignación son asociativos a la derecha, lo que significa que las operaciones se agrupan de derecha a izquierda.The assignment operators are right-associative, meaning that operations are grouped from right to left. Por ejemplo, una expresión con el formato a = b = c se evalúa como a = (b = c) .For example, an expression of the form a = b = c is evaluated as a = (b = c).
Asignación simpleSimple assignment
El = operador se denomina operador de asignación simple.The = operator is called the simple assignment operator.
Si el operando izquierdo de una asignación simple tiene el formato E.P o E[Ei] donde E tiene el tipo en tiempo de compilación dynamic , la asignación está enlazada dinámicamente (enlace dinámico).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). En este caso, el tipo en tiempo de compilación de la expresión de asignación es dynamic , y la resolución que se describe a continuación se realizará en tiempo de ejecución en función del tipo en tiempo de ejecución 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.
En una asignación simple, el operando derecho debe ser una expresión que se pueda convertir implícitamente al tipo del operando izquierdo.In a simple assignment, the right operand must be an expression that is implicitly convertible to the type of the left operand. La operación asigna el valor del operando derecho a la variable, la propiedad o el elemento indexador proporcionado por el operando izquierdo.The operation assigns the value of the right operand to the variable, property, or indexer element given by the left operand.
El resultado de una expresión de asignación simple es el valor asignado al operando izquierdo.The result of a simple assignment expression is the value assigned to the left operand. El resultado tiene el mismo tipo que el operando izquierdo y siempre se clasifica como un valor.The result has the same type as the left operand and is always classified as a value.
Si el operando izquierdo es una propiedad o un indexador, la propiedad o el indexador deben tener un set descriptor de acceso.If the left operand is a property or indexer access, the property or indexer must have a set accessor. Si no es así, se produce un error en tiempo de enlace.If this is not the case, a binding-time error occurs.
El procesamiento en tiempo de ejecución de una asignación simple del formulario x = y consta de los siguientes pasos:The run-time processing of a simple assignment of the form x = y consists of the following steps:
- Si
xse clasifica como una variable:Ifxis classified as a variable:xse evalúa para generar la variable.xis evaluated to produce the variable.yse evalúa y, si es necesario, se convierte al tipo dexmediante una conversión implícita (conversiones implícitas).yis evaluated and, if required, converted to the type ofxthrough an implicit conversion (Implicit conversions).- Si la variable proporcionada por
xes un elemento de matriz de un reference_type, se realiza una comprobación en tiempo de ejecución para asegurarse de que el valor calculado parayes compatible con la instancia de la matriz de quexes un elemento.If the variable given byxis an array element of a reference_type, a run-time check is performed to ensure that the value computed foryis compatible with the array instance of whichxis an element. La comprobación se realiza correctamente siyesnull, o si existe una conversión de referencia implícita (conversiones de referencia implícita) del tipo real de la instancia a la que se hace referencia enyel tipo de elemento real de la instancia de la matriz que contienex.The check succeeds ifyisnull, or if an implicit reference conversion (Implicit reference conversions) exists from the actual type of the instance referenced byyto the actual element type of the array instance containingx. De lo contrario, se produce una excepciónSystem.ArrayTypeMismatchException.Otherwise, aSystem.ArrayTypeMismatchExceptionis thrown. - El valor resultante de la evaluación y la conversión de
yse almacena en la ubicación especificada por la evaluación dex.The value resulting from the evaluation and conversion ofyis stored into the location given by the evaluation ofx.
- Si
xse clasifica como un acceso de propiedad o indizador:Ifxis classified as a property or indexer access:- La expresión de instancia (si
xno esstatic) y la lista de argumentos (sixes un acceso de indexador) asociadas axse evalúan, y los resultados se usan en lasetinvocación del descriptor de acceso subsiguiente.The instance expression (ifxis notstatic) and the argument list (ifxis an indexer access) associated withxare evaluated, and the results are used in the subsequentsetaccessor invocation. yse evalúa y, si es necesario, se convierte al tipo dexmediante una conversión implícita (conversiones implícitas).yis evaluated and, if required, converted to the type ofxthrough an implicit conversion (Implicit conversions).- El
setdescriptor de acceso dexse invoca con el valor calculado paraycomo suvalueargumento.Thesetaccessor ofxis invoked with the value computed foryas itsvalueargument.
- La expresión de instancia (si
Las reglas de covarianza de matriz (covarianza de matriz) permiten que un valor de un tipo de matriz A[] sea una referencia a una instancia de un tipo de matriz B[] , siempre que exista una conversión de referencia implícita de B a 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. Debido a estas reglas, la asignación a un elemento de matriz de un reference_type requiere una comprobación en tiempo de ejecución para asegurarse de que el valor que se está asignando es compatible con la instancia de la 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. En el ejemploIn the example
string[] sa = new string[10];
object[] oa = sa;
oa[0] = null; // Ok
oa[1] = "Hello"; // Ok
oa[2] = new ArrayList(); // ArrayTypeMismatchException
la última asignación provoca que System.ArrayTypeMismatchException se produzca una excepción porque no se ArrayList puede almacenar una instancia de en un elemento de 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[].
Cuando una propiedad o un indizador declarado en una struct_type es el destino de una asignación, la expresión de instancia asociada con el acceso a la propiedad o indizador debe estar clasificada como una variable.When a property or indexer declared in a struct_type is the target of an assignment, the instance expression associated with the property or indexer access must be classified as a variable. Si la expresión de instancia se clasifica como un valor, se produce un error en tiempo de enlace.If the instance expression is classified as a value, a binding-time error occurs. Debido al acceso a miembros, la misma regla también se aplica a los campos.Because of Member access, the same rule also applies to fields.
Dadas las declaraciones: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; }
}
}
en el ejemploin 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;
las asignaciones a p.X , p.Y , r.A y r.B se permiten porque p y r son variables.the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. Sin embargo, en el ejemploHowever, in the example
Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;
las asignaciones no son válidas, ya que r.A y r.B no son variables.the assignments are all invalid, since r.A and r.B are not variables.
Asignación compuestaCompound assignment
Si el operando izquierdo de una asignación compuesta tiene el formato E.P o E[Ei] donde E tiene el tipo en tiempo de compilación dynamic , la asignación está enlazada dinámicamente (enlace dinámico).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). En este caso, el tipo en tiempo de compilación de la expresión de asignación es dynamic , y la resolución que se describe a continuación se realizará en tiempo de ejecución en función del tipo en tiempo de ejecución 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.
Una operación del formulario x op= y se procesa aplicando la resolución de sobrecarga del operador binario (resolución de sobrecarga del operador binario) como si se hubiera escrito la operación 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. A continuación,Then,
- Si el tipo de valor devuelto del operador seleccionado es implícitamente convertible al tipo de
x, la operación se evalúa comox = x op y, excepto quexse evalúa solo una 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 thatxis evaluated only once. - De lo contrario, si el operador seleccionado es un operador predefinido, si el tipo de valor devuelto del operador seleccionado es convertible explícitamente al tipo de
x, y siyes implícitamente convertible al tipo dexo el operador es un operador de desplazamiento, la operación se evalúa comox = (T)(x op y), dondeTes el tipo dex, excepto quexse evalúa solo una 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 ifyis implicitly convertible to the type ofxor the operator is a shift operator, then the operation is evaluated asx = (T)(x op y), whereTis the type ofx, except thatxis evaluated only once. - De lo contrario, la asignación compuesta no es válida y se produce un error en tiempo de enlace.Otherwise, the compound assignment is invalid, and a binding-time error occurs.
El término "evaluado solo una vez" significa que en la evaluación de x op y , los resultados de cualquier expresión constitutiva de x se guardan temporalmente y se reutilizan al realizar la asignación a 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 ejemplo, en la asignación A()[B()] += C() , donde A es un método que devuelve int[] y B y C son métodos que devuelven int , los métodos se invocan solo una vez, en el orden 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.
Cuando el operando izquierdo de una asignación compuesta es un acceso a propiedad o a un indexador, la propiedad o el indexador deben tener un descriptor de acceso get y un set descriptor de acceso.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. Si no es así, se produce un error en tiempo de enlace.If this is not the case, a binding-time error occurs.
La segunda regla anterior permite x op= y evaluar como x = (T)(x op y) en determinados contextos.The second rule above permits x op= y to be evaluated as x = (T)(x op y) in certain contexts. La regla existe de forma que los operadores predefinidos se pueden utilizar como operadores compuestos cuando el operando izquierdo es de tipo sbyte , byte ,, short ushort o 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. Incluso cuando ambos argumentos son de uno de esos tipos, los operadores predefinidos producen un resultado de tipo int , tal y como se describe en promociones numéricas binarias.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. Por lo tanto, sin una conversión, no sería posible asignar el resultado al operando izquierdo.Thus, without a cast it would not be possible to assign the result to the left operand.
El efecto intuitivo de la regla para los operadores predefinidos es simplemente que x op= y se permite si x op y se permiten ambos tipos de y x = y .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. En el ejemploIn 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
la razón intuitiva de cada error es que una asignación simple correspondiente también habría sido un error.the intuitive reason for each error is that a corresponding simple assignment would also have been an error.
Esto también significa que las operaciones de asignación compuesta admiten operaciones de elevación.This also means that compound assignment operations support lifted operations. En el ejemploIn the example
int? i = 0;
i += 1; // Ok
se utiliza el operador de elevación +(int?,int?) .the lifted operator +(int?,int?) is used.
Asignación de eventosEvent assignment
Si el operando izquierdo de += un -= operador Or se clasifica como un acceso de evento, la expresión se evalúa como sigue:If the left operand of a += or -= operator is classified as an event access, then the expression is evaluated as follows:
- Expresión de instancia, si existe, del acceso al evento que se va a evaluar.The instance expression, if any, of the event access is evaluated.
- Se evalúa el operando derecho del
+=-=operador OR y, si es necesario, se convierte al tipo del operando izquierdo a través de una conversión implícita (conversiones 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). - Se invoca un descriptor de acceso de eventos del evento, con la lista de argumentos que consiste en el operando derecho, después de la evaluación y, si es necesario, conversión.An event accessor of the event is invoked, with argument list consisting of the right operand, after evaluation and, if necessary, conversion. Si el operador era
+=,addse invoca al descriptor de acceso; si el operador era-=,removese invoca al descriptor de acceso.If the operator was+=, theaddaccessor is invoked; if the operator was-=, theremoveaccessor is invoked.
Una expresión de asignación de eventos no produce un valor.An event assignment expression does not yield a value. Por lo tanto, una expresión de asignación de eventos solo es válida en el contexto de una statement_expression (instrucciones de expresión).Thus, an event assignment expression is valid only in the context of a statement_expression (Expression statements).
ExpressionExpression
Una expresión es una non_assignment_expression o una asignación.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
;
Expresiones constantesConstant expressions
Una constant_expression es una expresión que se puede evaluar por completo en tiempo de compilación.A constant_expression is an expression that can be fully evaluated at compile-time.
constant_expression
: expression
;
Una expresión constante debe ser el null literal o un valor con uno de los siguientes tipos: sbyte , byte , short , ushort , int , uint , long , ulong , char , float , double , decimal ,,, bool object string o cualquier tipo de enumeración.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. Solo se permiten las siguientes construcciones en expresiones constantes:Only the following constructs are permitted in constant expressions:
- Literales (incluido el
nullliteral).Literals (including thenullliteral). - Referencias a
constmiembros de tipos de clase y estructura.References toconstmembers of class and struct types. - Referencias a miembros de tipos de enumeración.References to members of enumeration types.
- Referencias a
constparámetros o variables localesReferences toconstparameters or local variables - Subexpresiones entre paréntesis, que son expresiones constantes.Parenthesized sub-expressions, which are themselves constant expressions.
- Expresiones de conversión, siempre que el tipo de destino sea uno de los tipos enumerados anteriormente.Cast expressions, provided the target type is one of the types listed above.
checked``uncheckedexpresiones ycheckedanduncheckedexpressions- Expresiones de valor predeterminadoDefault value expressions
- Expresiones NameNameof expressions
- Los
+-!~operadores unarios predefinidos,, y.The predefined+,-,!, and~unary operators. - Los operadores binarios predefinidos,,,,,,,,,,,,,,,,
+-*/%<<>>&|^&&||==!=<><=y>=, siempre que cada operando sea de un tipo enumerado anteriormente.The predefined+,-,*,/,%,<<,>>,&,|,^,&&,||,==,!=,<,>,<=, and>=binary operators, provided each operand is of a type listed above. ?:Operador condicional.The?:conditional operator.
Las siguientes conversiones se permiten en expresiones constantes:The following conversions are permitted in constant expressions:
- Conversiones de identidadIdentity conversions
- Conversiones numéricasNumeric conversions
- Conversiones de enumeraciónEnumeration conversions
- Conversiones de expresiones constantesConstant expression conversions
- Conversiones de referencia implícitas y explícitas, siempre que el origen de las conversiones sea una expresión constante que se evalúe como el valor null.Implicit and explicit reference conversions, provided that the source of the conversions is a constant expression that evaluates to the null value.
No se permiten otras conversiones, incluidas las conversiones Boxing, unboxing y de referencia implícita de valores no NULL en expresiones constantes.Other conversions including boxing, unboxing and implicit reference conversions of non-null values are not permitted in constant expressions. Por ejemplo:For example:
class C {
const object i = 5; // error: boxing conversion not permitted
const object str = "hello"; // error: implicit reference conversion
}
la inicialización de i es un error porque se requiere una conversión boxing.the initialization of i is an error because a boxing conversion is required. La inicialización de Str es un error porque se requiere una conversión de referencia implícita de un valor distinto de NULL.The initialization of str is an error because an implicit reference conversion from a non-null value is required.
Siempre que una expresión cumple los requisitos mencionados anteriormente, la expresión se evalúa en tiempo de compilación.Whenever an expression fulfills the requirements listed above, the expression is evaluated at compile-time. Esto es así incluso si la expresión es una subexpresión de una expresión mayor que contiene construcciones que no son constantes.This is true even if the expression is a sub-expression of a larger expression that contains non-constant constructs.
La evaluación en tiempo de compilación de las expresiones constantes utiliza las mismas reglas que la evaluación en tiempo de ejecución de expresiones no constantes, salvo que, en el caso de que la evaluación en tiempo de ejecución hubiera producido una excepción, la evaluación en tiempo de compilación provoca un error en tiempo de compilación.The compile-time evaluation of constant expressions uses the same rules as run-time evaluation of non-constant expressions, except that where run-time evaluation would have thrown an exception, compile-time evaluation causes a compile-time error to occur.
A menos que una expresión constante se coloque explícitamente en un unchecked contexto, los desbordamientos que se producen en operaciones aritméticas de tipo entero y en las conversiones durante la evaluación en tiempo de compilación de la expresión siempre producen errores en tiempo de compilación (expresiones constantes).Unless a constant expression is explicitly placed in an unchecked context, overflows that occur in integral-type arithmetic operations and conversions during the compile-time evaluation of the expression always cause compile-time errors (Constant expressions).
Las expresiones constantes se producen en los contextos que se enumeran a continuación.Constant expressions occur in the contexts listed below. En estos contextos, se produce un error en tiempo de compilación si una expresión no se puede evaluar por completo en tiempo de compilación.In these contexts, a compile-time error occurs if an expression cannot be fully evaluated at compile-time.
- Declaraciones de constantes (constantes).Constant declarations (Constants).
- Declaraciones de miembros de enumeración (miembros de enumeración).Enumeration member declarations (Enum members).
- Argumentos predeterminados de las listas de parámetros formales (parámetros de método)Default arguments of formal parameter lists (Method parameters)
caseEtiquetas de unaswitchinstrucción (la instrucción switch).caselabels of aswitchstatement (The switch statement).goto caseinstrucciones (instrucción Goto).goto casestatements (The goto statement).- Longitudes de dimensión en una expresión de creación de matriz (expresiones de creación de matrices) que incluye un inicializador.Dimension lengths in an array creation expression (Array creation expressions) that includes an initializer.
- Attributes (atributos).Attributes (Attributes).
Una conversión de expresión constante implícita (conversiones de expresión constante implícita) permite convertir una expresión constante de tipo en int sbyte ,, byte , short ushort , uint o ulong , siempre que el valor de la expresión constante esté dentro del intervalo del tipo de destino.An implicit constant expression conversion (Implicit constant expression conversions) permits a constant expression of type int to be converted to sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant expression is within the range of the destination type.
Expresiones booleanasBoolean expressions
Un Boolean_expression es una expresión que produce un resultado de tipo bool , ya sea directamente o a través de operator true la aplicación de en determinados contextos, tal y como se especifica en el siguiente.A boolean_expression is an expression that yields a result of type bool; either directly or through application of operator true in certain contexts as specified in the following.
boolean_expression
: expression
;
La expresión condicional de control de una if_statement (la instrucción if), while_statement (la instrucción while) , do_statement (la instrucción do) o for_Statement (la instrucción for) es una Boolean_expression.The controlling conditional expression of an if_statement (The if statement), while_statement (The while statement), do_statement (The do statement), or for_statement (The for statement) is a boolean_expression. La expresión condicional de control del ?: operador (operador condicional) sigue las mismas reglas que una Boolean_expression, pero por razones de precedencia de operadores se clasifica como conditional_or_expression.The controlling conditional expression of the ?: operator (Conditional operator) follows the same rules as a boolean_expression, but for reasons of operator precedence is classified as a conditional_or_expression.
Un Boolean_expression E es necesario para poder generar un valor de tipo bool , como se indica a continuación:A boolean_expression E is required to be able to produce a value of type bool, as follows:
- Si
Ese pueden convertir implícitamente abool, en tiempo de ejecución, se aplica la conversión implícita.IfEis implicitly convertible toboolthen at runtime that implicit conversion is applied. - De lo contrario, se utiliza la resolución de sobrecargas de operador unario (resolución de sobrecarga de operadores unarios) para encontrar una implementación óptima única de operador
trueenEy esa implementación se aplica en tiempo de ejecución.Otherwise, unary operator overload resolution (Unary operator overload resolution) is used to find a unique best implementation of operatortrueonE, and that implementation is applied at runtime. - Si no se encuentra ningún operador de este tipo, se produce un error en tiempo de enlace.If no such operator is found, a binding-time error occurs.
El tipo de DBBool estructura de tipo Boolean de base de datos proporciona un ejemplo de un tipo que implementa operator true y operator false .The DBBool struct type in Database boolean type provides an example of a type that implements operator true and operator false.