Coincidencia de patrones para C# 7Pattern Matching for C# 7
Las extensiones de coincidencia de patrones para C# permiten muchas de las ventajas de los tipos de datos algebraicos y la coincidencia de patrones de los lenguajes funcionales, pero de una manera que se integra sin problemas con la sensación del lenguaje subyacente.Pattern matching extensions for C# enable many of the benefits of algebraic data types and pattern matching from functional languages, but in a way that smoothly integrates with the feel of the underlying language. Las características básicas son: tipos de registros, que son tipos cuyo significado semántico se describe mediante la forma de los datos. y la coincidencia de patrones, que es un nuevo formulario de expresión que permite la descomposición de varios niveles de estos tipos de datos.The basic features are: record types, which are types whose semantic meaning is described by the shape of the data; and pattern matching, which is a new expression form that enables extremely concise multilevel decomposition of these data types. Los elementos de este enfoque están inspirados en las características relacionadas en los lenguajes de programación F # y Scala.Elements of this approach are inspired by related features in the programming languages F# and Scala.
Expresión isIs expression
El is operador se extiende para probar una expresión con un patrón.The is operator is extended to test an expression against a pattern.
relational_expression
: relational_expression 'is' pattern
;
Esta forma de relational_expression se suma a los formularios existentes en la especificación de C#.This form of relational_expression is in addition to the existing forms in the C# specification. Es un error en tiempo de compilación si el relational_expression a la izquierda del is token no designa un valor o no tiene un tipo.It is a compile-time error if the relational_expression to the left of the is token does not designate a value or does not have a type.
Cada identificador del patrón introduce una nueva variable local que se asigna definitivamente después de que el is operador sea true (es decir, se asigna definitivamente cuando es true).Every identifier of the pattern introduces a new local variable that is definitely assigned after the is operator is true (i.e. definitely assigned when true).
Nota: técnicamente existe una ambigüedad entre el tipo de una
is-expressionconstant_pattern y, cualquiera de los cuales puede ser un análisis válido de un identificador calificado.Note: There is technically an ambiguity between type in anis-expressionand constant_pattern, either of which might be a valid parse of a qualified identifier. Intentamos enlazarlo como un tipo para la compatibilidad con versiones anteriores del lenguaje; solo si se produce un error, se resuelve como hacemos en otros contextos, lo primero que se encontró (que debe ser una constante o un tipo).We try to bind it as a type for compatibility with previous versions of the language; only if that fails do we resolve it as we do in other contexts, to the first thing found (which must be either a constant or a type). Esta ambigüedad solo está presente en la parte derecha de unaisexpresión.This ambiguity is only present on the right-hand-side of anisexpression.
PatronesPatterns
Los patrones se usan en el is operador y en una switch_statement para expresar la forma de los datos con los que se van a comparar los datos entrantes.Patterns are used in the is operator and in a switch_statement to express the shape of data against which incoming data is to be compared. Los patrones pueden ser recursivos para que se puedan comparar partes de los datos con subpatrones.Patterns may be recursive so that parts of the data may be matched against sub-patterns.
pattern
: declaration_pattern
| constant_pattern
| var_pattern
;
declaration_pattern
: type simple_designation
;
constant_pattern
: shift_expression
;
var_pattern
: 'var' simple_designation
;
Nota: técnicamente existe una ambigüedad entre el tipo de una
is-expressionconstant_pattern y, cualquiera de los cuales puede ser un análisis válido de un identificador calificado.Note: There is technically an ambiguity between type in anis-expressionand constant_pattern, either of which might be a valid parse of a qualified identifier. Intentamos enlazarlo como un tipo para la compatibilidad con versiones anteriores del lenguaje; solo si se produce un error, se resuelve como hacemos en otros contextos, lo primero que se encontró (que debe ser una constante o un tipo).We try to bind it as a type for compatibility with previous versions of the language; only if that fails do we resolve it as we do in other contexts, to the first thing found (which must be either a constant or a type). Esta ambigüedad solo está presente en la parte derecha de unaisexpresión.This ambiguity is only present on the right-hand-side of anisexpression.
Modelo de declaraciónDeclaration pattern
El declaration_pattern ambos comprueba que una expresión es de un tipo determinado y la convierte a ese tipo si la prueba se realiza correctamente.The declaration_pattern both tests that an expression is of a given type and casts it to that type if the test succeeds. Si el simple_designation es un identificador, introduce una variable local del tipo especificado denominado por el identificador especificado.If the simple_designation is an identifier, it introduces a local variable of the given type named by the given identifier. Esa variable local se asigna definitivamente cuando el resultado de la operación de coincidencia de patrones es true.That local variable is definitely assigned when the result of the pattern-matching operation is true.
declaration_pattern
: type simple_designation
;
La semántica en tiempo de ejecución de esta expresión es que prueba el tipo en tiempo de ejecución del operando del lado izquierdo relational_expression en el tipo del patrón.The runtime semantic of this expression is that it tests the runtime type of the left-hand relational_expression operand against the type in the pattern. Si es de ese tipo en tiempo de ejecución (o algún subtipo), el resultado de is operator es true .If it is of that runtime type (or some subtype), the result of the is operator is true. Declara una nueva variable local denominada por el identificador al que se asigna el valor del operando izquierdo cuando el resultado es true .It declares a new local variable named by the identifier that is assigned the value of the left-hand operand when the result is true.
Ciertas combinaciones de tipo estático del lado izquierdo y del tipo especificado se consideran incompatibles y producen un error en tiempo de compilación.Certain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. Se dice que un valor de tipo estático E es compatible con el tipo T si existe una conversión de identidad, una conversión de referencia implícita, una conversión boxing, una conversión de referencia explícita o una conversión unboxing de E a T .A value of static type E is said to be pattern compatible with the type T if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion from E to T. Es un error en tiempo de compilación si una expresión de tipo E no es compatible con el tipo en un patrón de tipo con el que se encuentra una coincidencia.It is a compile-time error if an expression of type E is not pattern compatible with the type in a type pattern that it is matched with.
Nota: en C# 7,1 se amplía esto para permitir una operación de coincidencia de patrones si el tipo de entrada o el tipo
Tes un tipo abierto.Note: In C# 7.1 we extend this to permit a pattern-matching operation if either the input type or the typeTis an open type. Este párrafo se sustituye por lo siguiente:This paragraph is replaced by the following:Ciertas combinaciones de tipo estático del lado izquierdo y del tipo especificado se consideran incompatibles y producen un error en tiempo de compilación.Certain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. Se dice que un valor de tipo estático
Ees compatible con el tipoTsi existe una conversión de identidad, una conversión de referencia implícita, una conversión boxing, una conversión de referencia explícita o una conversión unboxing deEaT, o bien, siEoTes un tipo abierto.A value of static typeEis said to be pattern compatible with the typeTif there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion fromEtoT, or if eitherEorTis an open type. Es un error en tiempo de compilación si una expresión de tipoEno es compatible con el tipo en un patrón de tipo con el que se encuentra una coincidencia.It is a compile-time error if an expression of typeEis not pattern compatible with the type in a type pattern that it is matched with.
El modelo de declaración es útil para realizar pruebas de tipo en tiempo de ejecución de tipos de referencia y reemplaza la expresiónThe declaration pattern is useful for performing run-time type tests of reference types, and replaces the idiom
var v = expr as Type;
if (v != null) { // code using v }
Con el poco más concisoWith the slightly more concise
if (expr is Type v) { // code using v }
Es un error si el tipo es un tipo de valor que acepta valores NULL.It is an error if type is a nullable value type.
El modelo de declaración se puede usar para probar valores de tipos que aceptan valores NULL: un valor de tipo Nullable<T> (o una conversión boxing T ) coincide con un patrón de tipo T2 id si el valor no es NULL y el tipo de T2 es T , o algún tipo base o interfaz de T .The declaration pattern can be used to test values of nullable types: a value of type Nullable<T> (or a boxed T) matches a type pattern T2 id if the value is non-null and the type of T2 is T, or some base type or interface of T. Por ejemplo, en el fragmento de códigoFor example, in the code fragment
int? x = 3;
if (x is int v) { // code using v }
La condición de la if instrucción está true en tiempo de ejecución y la variable v contiene el valor 3 de tipo int dentro del bloque.The condition of the if statement is true at runtime and the variable v holds the value 3 of type int inside the block.
Patrón de constanteConstant pattern
constant_pattern
: shift_expression
;
Un patrón de constante prueba el valor de una expresión con respecto a un valor constante.A constant pattern tests the value of an expression against a constant value. La constante puede ser cualquier expresión constante, como un literal, el nombre de una variable declarada const , una constante de enumeración o una typeof expresión.The constant may be any constant expression, such as a literal, the name of a declared const variable, or an enumeration constant, or a typeof expression.
Si tanto e como c son de tipos enteros, se considera que el patrón coincide si el resultado de la expresión e == c es true .If both e and c are of integral types, the pattern is considered matched if the result of the expression e == c is true.
De lo contrario, el patrón se considera coincidente si object.Equals(e, c) devuelve true .Otherwise the pattern is considered matching if object.Equals(e, c) returns true. En este caso, se trata de un error en tiempo de compilación si el tipo estático de e no es compatible con el tipo de la constante.In this case it is a compile-time error if the static type of e is not pattern compatible with the type of the constant.
Patrón varVar pattern
var_pattern
: 'var' simple_designation
;
Una expresión e coincide con un var_pattern siempre.An expression e matches a var_pattern always. En otras palabras, una coincidencia con un patrón var siempre se realiza correctamente.In other words, a match to a var pattern always succeeds. Si el simple_designation es un identificador, en tiempo de ejecución el valor de e se enlaza a una variable local recién introducida.If the simple_designation is an identifier, then at runtime the value of e is bound to a newly introduced local variable. El tipo de la variable local es el tipo estático de e.The type of the local variable is the static type of e.
Es un error si el nombre se var enlaza a un tipo.It is an error if the name var binds to a type.
Instrucción switchSwitch statement
La switch instrucción se extiende para seleccionar la ejecución del primer bloque que tiene un patrón asociado que coincide con la expresión switch.The switch statement is extended to select for execution the first block having an associated pattern that matches the switch expression.
switch_label
: 'case' complex_pattern case_guard? ':'
| 'case' constant_expression case_guard? ':'
| 'default' ':'
;
case_guard
: 'when' expression
;
No se define el orden en el que se buscan coincidencias con los patrones.The order in which patterns are matched is not defined. Se permite que un compilador coincida con los patrones desordenados y reutilizar los resultados de los patrones ya coincidentes para calcular el resultado de la coincidencia de otros patrones.A compiler is permitted to match patterns out of order, and to reuse the results of already matched patterns to compute the result of matching of other patterns.
Si hay una protección de casos , su expresión es de tipo bool .If a case-guard is present, its expression is of type bool. Se evalúa como una condición adicional que se debe satisfacer para que el caso se considere satisfecho.It is evaluated as an additional condition that must be satisfied for the case to be considered satisfied.
Es un error si un switch_label puede no tener ningún efecto en el tiempo de ejecución porque su patrón está en los casos anteriores.It is an error if a switch_label can have no effect at runtime because its pattern is subsumed by previous cases. [TODO: deberíamos ser más precisos sobre las técnicas que el compilador necesita usar para alcanzar esta resolución.][TODO: We should be more precise about the techniques the compiler is required to use to reach this judgment.]
Una variable de patrón declarada en un switch_label se asigna definitivamente en su bloque case si y solo si ese bloque Case contiene exactamente un switch_label.A pattern variable declared in a switch_label is definitely assigned in its case block if and only if that case block contains precisely one switch_label.
[TODO: deberíamos especificar Cuándo se puede obtener acceso a un bloque switch .][TODO: We should specify when a switch block is reachable.]
Ámbito de las variables de patrónScope of pattern variables
El ámbito de una variable declarada en un patrón es el siguiente:The scope of a variable declared in a pattern is as follows:
- Si el patrón es una etiqueta de caso, el ámbito de la variable es el bloque de casos.If the pattern is a case label, then the scope of the variable is the case block.
En caso contrario, la variable se declara en una expresión is_pattern y su ámbito se basa en la construcción que incluye inmediatamente la expresión que contiene la expresión is_pattern de la siguiente manera:Otherwise the variable is declared in an is_pattern expression, and its scope is based on the construct immediately enclosing the expression containing the is_pattern expression as follows:
- Si la expresión se encuentra en una expresión lambda con cuerpo de expresión, su ámbito es el cuerpo de la lambda.If the expression is in an expression-bodied lambda, its scope is the body of the lambda.
- Si la expresión se encuentra en un método o propiedad con forma de expresión, su ámbito es el cuerpo del método o propiedad.If the expression is in an expression-bodied method or property, its scope is the body of the method or property.
- Si la expresión está en una
whencláusula de unacatchcláusula, su ámbito es esacatchcláusula.If the expression is in awhenclause of acatchclause, its scope is thatcatchclause. - Si la expresión se encuentra en un iteration_statement, su ámbito es simplemente esa instrucción.If the expression is in an iteration_statement, its scope is just that statement.
- De lo contrario, si la expresión está en otra forma de instrucción, su ámbito es el ámbito que contiene la instrucción.Otherwise if the expression is in some other statement form, its scope is the scope containing the statement.
Con el fin de determinar el ámbito, se considera que una embedded_statement está en su propio ámbito.For the purpose of determining the scope, an embedded_statement is considered to be in its own scope. Por ejemplo, la gramática de una if_statement esFor example, the grammar for an if_statement is
if_statement
: 'if' '(' boolean_expression ')' embedded_statement
| 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement
;
Por tanto, si la instrucción controlada de un if_statement declara una variable de patrón, su ámbito está restringido a ese embedded_statement:So if the controlled statement of an if_statement declares a pattern variable, its scope is restricted to that embedded_statement:
if (x) M(y is var z);
En este caso, el ámbito de z es la instrucción incrustada M(y is var z); .In this case the scope of z is the embedded statement M(y is var z);.
Otros casos son errores por otros motivos (por ejemplo, en el valor predeterminado de un parámetro o en un atributo, ambos son un error porque esos contextos requieren una expresión constante).Other cases are errors for other reasons (e.g. in a parameter's default value or an attribute, both of which are an error because those contexts require a constant expression).
En C# 7,3 hemos agregado los siguientes contextos en los que se puede declarar una variable de patrón:In C# 7.3 we added the following contexts in which a pattern variable may be declared:
- Si la expresión se encuentra en un inicializador de constructor, su ámbito es el inicializador del constructor y el cuerpo del constructor.If the expression is in a constructor initializer, its scope is the constructor initializer and the constructor's body.
- Si la expresión se encuentra en un inicializador de campo, su ámbito es el equals_value_clause en el que aparece.If the expression is in a field initializer, its scope is the equals_value_clause in which it appears.
- Si la expresión se encuentra en una cláusula de consulta que se especifica para traducirse en el cuerpo de una expresión lambda, su ámbito es simplemente esa expresión.If the expression is in a query clause that is specified to be translated into the body of a lambda, its scope is just that expression.
Cambios en la desambiguación sintácticaChanges to syntactic disambiguation
Hay situaciones en las que se implican genéricos en los que la gramática de C# es ambigua y en la especificación del lenguaje se indica cómo resolver esas ambigüedades:There are situations involving generics where the C# grammar is ambiguous, and the language spec says how to resolve those ambiguities:
7.6.5.2 ambigüedades de la gramática7.6.5.2 Grammar ambiguities
Las producciones de nombre simple (§ 7.6.3) y acceso a miembros (§ 7.6.5) pueden dar lugar a ambigüedades en la gramática de expresiones.The productions for simple-name (§7.6.3) and member-access (§7.6.5) 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
Fcon dos argumentos,G < AyB > (7).could be interpreted as a call toFwith two arguments,G < AandB > (7). Como alternativa, podría interpretarse como una llamada aFcon un argumento, que es una llamada a un método genéricoGcon dos argumentos de tipo y un argumento normal.Alternatively, it could be interpreted as a call toFwith one argument, which is a call to a generic methodGwith two type arguments and one regular argument.
Si se puede analizar una secuencia de tokens (en contexto) como un nombre simple (§ 7.6.3), acceso a miembro (§ 7.6.5) o acceso a miembro de puntero (§ 18.5.2) que termina con una lista de argumentos de tipo (§ 4.4.1), se examina el token inmediatamente posterior al token de cierre
>.If a sequence of tokens can be parsed (in context) as a simple-name (§7.6.3), member-access (§7.6.5), or pointer-member-access (§18.5.2) ending with a type-argument-list (§4.4.1), the token immediately following the closing>token is examined. Si es uno deIf it is one of( ) ] } : ; , . ? == != | ^a continuación, la lista de argumentos de tipo se conserva como parte del acceso simple, de acceso a miembros o de miembro de puntero , 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, la lista de argumentos de tipo no se considera parte del nombre simple, acceso a miembros o > puntero- miembro-acceso, incluso si no hay otro posible análisis 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 lista de argumentos de tipo en un nombre de espacio de nombres o-tipo (§ 3,8).Note that these rules are not applied when parsing a type-argument-list in a namespace-or-type-name (§3.8). La instrucciónThe statement
F(G<A,B>(7));, según esta regla, se interpretará como una llamada a
Fcon un argumento, que es una llamada a un método genéricoGcon dos argumentos de tipo y un argumento normal.will, according to this rule, be interpreted as a call toFwith one argument, which is a call to a generic methodGwith two type arguments and one regular argument. Las instruccionesThe statementsF(G < A, B > 7); F(G < A, B >> 7);cada uno de ellos se interpretará como una llamada a
Fcon dos argumentos.will each be interpreted as a call toFwith two arguments. La instrucciónThe statementx = 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 nombre simple con una lista de argumentos de tipo 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 writtenx = (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 statementx = y is C<T> + z;los tokens
C<T>se interpretan como un espacio de nombres o un nombre de tipo con una lista de argumentos de tipo.the tokensC<T>are interpreted as a namespace-or-type-name with a type-argument-list.
Hay una serie de cambios que se introducen en C# 7 que hacen que estas reglas de desambiguación dejen de ser suficientes para controlar la complejidad del lenguaje.There are a number of changes being introduced in C# 7 that make these disambiguation rules no longer sufficient to handle the complexity of the language.
Declaraciones de variable outOut variable declarations
Ahora es posible declarar una variable en un argumento out:It is now possible to declare a variable in an out argument:
M(out Type name);
Sin embargo, el tipo puede ser genérico:However, the type may be generic:
M(out A<B> name);
Dado que la gramática de idioma para el argumento usa Expression, este contexto está sujeto a la regla de desambiguación.Since the language grammar for the argument uses expression, this context is subject to the disambiguation rule. En este caso, el cierre va > seguido de un identificador, que no es uno de los tokens que permite que se trate como una lista de argumentos de tipo.In this case the closing > is followed by an identifier, which is not one of the tokens that permits it to be treated as a type-argument-list. Por lo tanto, se propone Agregar el identificador al conjunto de tokens que desencadena la desambiguación en una lista de argumentos de tipo.I therefore propose to add identifier to the set of tokens that triggers the disambiguation to a type-argument-list.
Tuplas y declaraciones de desconstrucciónTuples and deconstruction declarations
Un literal de tupla se ejecuta exactamente en el mismo problema.A tuple literal runs into exactly the same issue. Considere la expresión de tupla.Consider the tuple expression
(A < B, C > D, E < F, G > H)
En las reglas anteriores de C# 6 para analizar una lista de argumentos, esto se analizaría como una tupla con cuatro elementos, empezando por A < B como primer.Under the old C# 6 rules for parsing an argument list, this would parse as a tuple with four elements, starting with A < B as the first. Sin embargo, cuando esto aparece a la izquierda de una desconstrucción, queremos que la desambiguación se desencadene por el token del identificador como se describió anteriormente:However, when this appears on the left of a deconstruction, we want the disambiguation triggered by the identifier token as described above:
(A<B,C> D, E<F,G> H) = e;
Se trata de una declaración de desconstrucción que declara dos variables, la primera de las cuales es de tipo A<B,C> y con nombre D .This is a deconstruction declaration which declares two variables, the first of which is of type A<B,C> and named D. En otras palabras, el literal de tupla contiene dos expresiones, cada una de las cuales es una expresión de declaración.In other words, the tuple literal contains two expressions, each of which is a declaration expression.
Para simplificar la especificación y el compilador, propongo que este literal de tupla se analice como una tupla de dos elementos dondequiera que aparezca (ya sea o no aparece en el lado izquierdo de una asignación).For simplicity of the specification and compiler, I propose that this tuple literal be parsed as a two-element tuple wherever it appears (whether or not it appears on the left-hand-side of an assignment). Esto sería un resultado natural de la desambiguación descrita en la sección anterior.That would be a natural result of the disambiguation described in the previous section.
Coincidencia de patronesPattern-matching
La coincidencia de patrones introduce un nuevo contexto en el que se produce la ambigüedad del tipo de expresión.Pattern matching introduces a new context where the expression-type ambiguity arises. Anteriormente, el lado derecho de un is operador era un tipo.Previously the right-hand-side of an is operator was a type. Ahora puede ser un tipo o una expresión, y si es un tipo, puede ir seguido de un identificador.Now it can be a type or expression, and if it is a type it may be followed by an identifier. Técnicamente, esto puede cambiar el significado del código existente:This can, technically, change the meaning of existing code:
var x = e is T < A > B;
Esto podría analizarse en reglas de C# 6 comoThis could be parsed under C#6 rules as
var x = ((e is T) < A) > B;
pero bajo bajo las reglas de C# 7 (con la desambiguación propuesta anteriormente) se analizaría comobut under under C#7 rules (with the disambiguation proposed above) would be parsed as
var x = e is T<A> B;
que declara una variable B de tipo T<A> .which declares a variable B of type T<A>. Afortunadamente, los compiladores nativo y Roslyn tienen un error por el que dan un error de sintaxis en el código de C# 6.Fortunately, the native and Roslyn compilers have a bug whereby they give a syntax error on the C#6 code. Por lo tanto, este cambio importante concreto no es un problema.Therefore this particular breaking change is not a concern.
La coincidencia de patrones introduce tokens adicionales que deben impulsar la resolución de ambigüedades al seleccionar un tipo.Pattern-matching introduces additional tokens that should drive the ambiguity resolution toward selecting a type. Los siguientes ejemplos de código de C# 6 válido existente se interrumpirían sin reglas de desambiguación adicionales:The following examples of existing valid C#6 code would be broken without additional disambiguation rules:
var x = e is A<B> && f; // &&
var x = e is A<B> || f; // ||
var x = e is A<B> & f; // &
var x = e is A<B>[]; // [
Cambio propuesto en la regla de desambiguaciónProposed change to the disambiguation rule
Propongo revisar la especificación para cambiar la lista de tokens de ambigüedad deI propose to revise the specification to change the list of disambiguating tokens from
( ) ] } : ; , . ? == != | ^
ento
( ) ] } : ; , . ? == != | ^ && || & [
Y, en ciertos contextos, tratamos el identificador como un token de ambigüedad.And, in certain contexts, we treat identifier as a disambiguating token. Esos contextos son donde la secuencia de tokens que se va a ambigüedadr está inmediatamente precedida por una de las palabras clave is , case , o out , o cuando se analiza el primer elemento de un literal de tupla (en cuyo caso los tokens van precedidos de ( o : y el identificador va seguido de , ) o un elemento subsiguiente de un literal de tupla.Those contexts are where the sequence of tokens being disambiguated is immediately preceded by one of the keywords is, case, or out, or arises while parsing the first element of a tuple literal (in which case the tokens are preceded by ( or : and the identifier is followed by a ,) or a subsequent element of a tuple literal.
Regla de desambiguación modificadaModified disambiguation rule
La regla de desambiguación revisada sería similar a la siguienteThe revised disambiguation rule would be something like this
Si se puede analizar una secuencia de tokens (en contexto) como un nombre simple (§ 7.6.3), el acceso a miembros (§ 7.6.5) o el acceso de miembro de puntero (§ 18.5.2) que termina con una lista de argumentos de tipo (§ 4.4.1), se examina el token inmediatamente posterior al token de cierre
>para ver si esIf a sequence of tokens can be parsed (in context) as a simple-name (§7.6.3), member-access (§7.6.5), or pointer-member-access (§18.5.2) ending with a type-argument-list (§4.4.1), the token immediately following the closing>token is examined, to see if it is
- Uno de
( ) ] } : ; , . ? == != | ^ && || & [; oOne of( ) ] } : ; , . ? == != | ^ && || & [; or- Uno de los operadores relacionales
< > <= >= is as; oOne of the relational operators< > <= >= is as; or- Una palabra clave de consulta contextual que aparece dentro de una expresión de consulta; deA contextual query keyword appearing inside a query expression; or
- En ciertos contextos, tratamos el identificador como un token de ambigüedad.In certain contexts, we treat identifier as a disambiguating token. Estos contextos son donde la secuencia de tokens que se va a inaprovechar está inmediatamente precedida por una de las palabras clave
is, ocaseout, o cuando se analiza el primer elemento de un literal de tupla (en cuyo caso los tokens van precedidos de(o:y el identificador va seguido de un,) o un elemento subsiguiente de un literal de tupla.Those contexts are where the sequence of tokens being disambiguated is immediately preceded by one of the keywordsis,caseorout, or arises while parsing the first element of a tuple literal (in which case the tokens are preceded by(or:and the identifier is followed by a,) or a subsequent element of a tuple literal.Si el token siguiente se encuentra entre esta lista o un identificador en un contexto de este tipo, la lista de argumentos de tipo se conserva como parte del nombre simple, acceso a miembros o puntero a miembro de puntero , y se descarta cualquier otro posible análisis de la secuencia de tokens.If the following token is among this list, or an identifier in such a context, 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, la lista de argumentos de tipo no se considera parte del acceso simple, de acceso a miembros o de miembro de puntero, incluso si no hay otro posible análisis 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 lista de argumentos de tipo en un nombre de espacio de nombres o-tipo (§ 3,8).Note that these rules are not applied when parsing a type-argument-list in a namespace-or-type-name (§3.8).
Cambios importantes debidos a esta propuestaBreaking changes due to this proposal
No se conoce ningún cambio importante debido a esta regla de desambiguación propuesta.No breaking changes are known due to this proposed disambiguation rule.
Ejemplos interesantesInteresting examples
Estos son algunos resultados interesantes de estas reglas de desambiguación:Here are some interesting results of these disambiguation rules:
La expresión (A < B, C > D) es una tupla con dos elementos, cada una de las cuales es una comparación.The expression (A < B, C > D) is a tuple with two elements, each a comparison.
La expresión (A<B,C> D, E) es una tupla con dos elementos, el primero de los cuales es una expresión de declaración.The expression (A<B,C> D, E) is a tuple with two elements, the first of which is a declaration expression.
La invocación M(A < B, C > D, E) tiene tres argumentos.The invocation M(A < B, C > D, E) has three arguments.
La invocación M(out A<B,C> D, E) tiene dos argumentos, el primero de los cuales es una out declaración.The invocation M(out A<B,C> D, E) has two arguments, the first of which is an out declaration.
La expresión e is A<B> C utiliza una expresión de declaración.The expression e is A<B> C uses a declaration expression.
La etiqueta de caso case A<B> C: utiliza una expresión de declaración.The case label case A<B> C: uses a declaration expression.
Algunos ejemplos de coincidencia de patronesSome examples of pattern matching
Is-AsIs-As
Podemos reemplazar la expresiónWe can replace the idiom
var v = expr as Type;
if (v != null) {
// code using v
}
Con el aspecto más conciso y directoWith the slightly more concise and direct
if (expr is Type v) {
// code using v
}
Prueba de valores NULLTesting nullable
Podemos reemplazar la expresiónWe can replace the idiom
Type? v = x?.y?.z;
if (v.HasValue) {
var value = v.GetValueOrDefault();
// code using value
}
Con el aspecto más conciso y directoWith the slightly more concise and direct
if (x?.y?.z is Type value) {
// code using value
}
Simplificación aritméticaArithmetic simplification
Supongamos que definimos un conjunto de tipos recursivos para representar expresiones (según una propuesta independiente):Suppose we define a set of recursive types to represent expressions (per a separate proposal):
abstract class Expr;
class X() : Expr;
class Const(double Value) : Expr;
class Add(Expr Left, Expr Right) : Expr;
class Mult(Expr Left, Expr Right) : Expr;
class Neg(Expr Value) : Expr;
Ahora se puede definir una función para calcular el derivado (no reducido) de una expresión:Now we can define a function to compute the (unreduced) derivative of an expression:
Expr Deriv(Expr e)
{
switch (e) {
case X(): return Const(1);
case Const(*): return Const(0);
case Add(var Left, var Right):
return Add(Deriv(Left), Deriv(Right));
case Mult(var Left, var Right):
return Add(Mult(Deriv(Left), Right), Mult(Left, Deriv(Right)));
case Neg(var Value):
return Neg(Deriv(Value));
}
}
Un Simplificador de expresiones muestra patrones posicionales:An expression simplifier demonstrates positional patterns:
Expr Simplify(Expr e)
{
switch (e) {
case Mult(Const(0), *): return Const(0);
case Mult(*, Const(0)): return Const(0);
case Mult(Const(1), var x): return Simplify(x);
case Mult(var x, Const(1)): return Simplify(x);
case Mult(Const(var l), Const(var r)): return Const(l*r);
case Add(Const(0), var x): return Simplify(x);
case Add(var x, Const(0)): return Simplify(x);
case Add(Const(var l), Const(var r)): return Const(l+r);
case Neg(Const(var k)): return Const(-k);
default: return e;
}
}