Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
11.1 General
Un patrón es una forma sintáctica que se puede usar con el is operador (§12.15.12), en un switch_statement (§13.8.3) y en un switch_expression (§12.12) para expresar la forma de datos con los que se van a comparar los datos entrantes. Los patrones pueden ser recursivos, de modo que las partes de los datos se puedan comparar con subprocesos.
Un patrón se prueba con un valor en varios contextos:
- En una instrucción switch, el patrón de una etiqueta case se prueba con la expresión de la instrucción switch.
- En un operador is-pattern , el patrón del lado derecho se prueba con la expresión de la izquierda.
- En una expresión switch, el patrón de un switch_expression_arm se prueba con la expresión en el lado izquierdo de switch-expression.
- En contextos anidados, el subproceso se prueba con valores recuperados de propiedades, campos o indexados de otros valores de entrada, según el formulario de patrón.
El valor con el que se prueba un patrón se denomina valor de entrada de patrón.
11.2 Formularios de patrón
11.2.1 General
Un patrón puede tener una de las formas siguientes:
pattern
: logical_pattern
;
primary_pattern
: parenthesized_pattern
| declaration_pattern
| constant_pattern
| var_pattern
| positional_pattern
| property_pattern
| discard_pattern
| type_pattern
| relational_pattern
;
parenthesized_pattern
: '(' pattern ')'
;
La '(' pattern ')' producción permite incluir un patrón entre paréntesis para aplicar el orden de evaluación entre patrones combinados mediante uno de los logical_patterns.
Algunos patronespueden dar lugar a la declaración de una variable local.
Cada formulario de patrón define el conjunto de tipos para los valores de entrada a los que se puede aplicar el patrón. Un patrón P es aplicable a un tipo T si T está entre los tipos cuyos valores puede coincidir el patrón. Es un error en tiempo de compilación si un patrón P aparece en un programa para que coincida con un valor de entrada de patrón (§11.1) de tipo T si P no es aplicable a T.
Ejemplo: el ejemplo siguiente genera un error en tiempo de compilación porque el tipo de tiempo de compilación de
vesTextReader. Una variable de tipoTextReadernunca puede tener un valor compatible constring:TextReader v = Console.In; // compile-time type of 'v' is 'TextReader' if (v is string) // compile-time error { // code assuming v is a string }Sin embargo, lo siguiente no genera un error en tiempo de compilación porque el tipo de tiempo de compilación de
vesobject. Una variable de tipoobjectpodría tener un valor compatible con la referencia constring:object v = Console.In; if (v is string s) { // code assuming v is a string }ejemplo final
Cada formulario de patrón define el conjunto de valores para los que el patrón coincide con el valor en tiempo de ejecución.
No se especifica el orden de evaluación de operaciones y efectos secundarios durante la coincidencia de patrones (llamadas a , accesos a Deconstructpropiedades e invocaciones de métodos en System.ITuple).
11.2.2 Patrón de declaración
Se usa un declaration_pattern para probar que un valor tiene un tipo determinado y, si la prueba se realiza correctamente, para proporcionar opcionalmente el valor en una variable de ese tipo.
declaration_pattern
: type simple_designation
;
simple_designation
: discard_designation
| single_variable_designation
;
discard_designation
: '_'
;
single_variable_designation
: identifier
;
Un simple_designation con el token _ se considerará un discard_designation en lugar de un single_variable_designation.
El tipo en tiempo de ejecución del valor se prueba con el tipo en el patrón mediante las mismas reglas especificadas en el operador is-type (§12.15.12.1). Si la prueba se realiza correctamente, el patrón coincide con ese valor. Es un error en tiempo de compilación si el tipo es un tipo de valor que acepta valores NULL (§8.3.12) o un tipo de referencia que acepta valores NULL (§8.9.3). Este formulario de patrón nunca coincide con un null valor.
Nota: La expresión
e is Tis-type y el patróne is T _de declaración son equivalentes cuandoTno es un tipo que acepta valores NULL. nota final
Dado un valor de entrada de patrón (§11.1) e, si el simple_designation es discard_designation, denota un descarte (§9.2.9.2) y el valor de e no está enlazado a nada. (Aunque una variable declarada con el nombre _ puede estar en el ámbito en ese momento, esa variable con nombre no se ve en este contexto). De lo contrario, si el simple_designation es single_variable_designation, se introduce una variable local (§9.2.9) del tipo especificado denominado por el identificador especificado. A esa variable local se le asigna el valor del valor de entrada del patrón cuando el patrón coincide con el valor.
Ciertas combinaciones de tipo estático del valor de entrada de patrón y el tipo especificado se consideran incompatibles y producen un error en tiempo de compilación. Se dice que un valor de tipo E estático es compatible con el T patrón si existe una conversión de identidad, una conversión de referencia implícita o explícita, una conversión boxing, una conversión de conversión unboxing o una conversión implícita o explícita de tipo de valor que acepta valores NULL desde E a T, o si o ET es un tipo abierto (§8.4.3). Un patrón de declaración que asigna un nombre a un tipo T es aplicable ael patrón .
Nota: La compatibilidad con tipos abiertos puede ser más útil al comprobar tipos que pueden ser tipos de estructura o clase, y se debe evitar la conversión boxing. nota final
Ejemplo: el patrón de declaración es útil para realizar pruebas de tipos en tiempo de ejecución de tipos de referencia y reemplaza la expresión
var v = expr as Type; if (v != null) { /* code using v */ }con un poco más conciso
if (expr is Type v) { /* code using v */ }ejemplo final
Ejemplo: El patrón de declaración se puede usar para probar valores de tipos que aceptan valores NULL: un valor de tipo
Nullable<T>(o un boxedT) coincide con un patrónT2 idde tipo si el valor no es NULL yT2esT, o algún tipo base o interfaz deT. Por ejemplo, en el fragmento de códigoint? x = 3; if (x is int v) { /* code using v */ }La condición de la
ifinstrucción estátrueen tiempo de ejecución y la variablevcontiene el valor3de tipointdentro del bloque. Después del bloque, la variablevestá en el ámbito, pero no está asignada definitivamente. ejemplo final
11.2.3 Patrón constante
Un constant_pattern se usa para probar el valor de un valor de entrada de patrón (§11.1) con el valor constante especificado.
constant_pattern
: constant_expression
;
Un patrón P de constante se aplica a un tipo T si hay una conversión implícita de la expresión constante de P al tipo T.
Para un patrón Pconstante, su valor convertido es
- si el tipo del valor de entrada del patrón es un tipo entero o un tipo de enumeración, el valor constante del patrón se convierte en ese tipo; de otra manera
- si el tipo del valor de entrada del patrón es la versión que acepta valores NULL de un tipo entero o un tipo de enumeración, el valor constante del patrón se convierte en su tipo subyacente; de otra manera
- el valor del valor constante del patrón.
Dado un valor de entrada de patrón e y un patrón P constante con valor convertido v,
- si e tiene tipo entero o tipo de enumeración, o una forma que acepta valores NULL de uno de ellos, y v tiene un tipo entero, el patrón
Pcoincide con el valor e si el resultado de la expresióne == vestrue; de lo contrario, - el patrón
Pcoincide con el valor e siobject.Equals(e, v)devuelvetrue.
Ejemplo: la
switchinstrucción del método siguiente usa cinco patrones constantes en sus etiquetas de mayúsculas y minúsculas.static decimal GetGroupTicketPrice(int visitorCount) { switch (visitorCount) { case 1: return 12.0m; case 2: return 20.0m; case 3: return 27.0m; case 4: return 32.0m; case 0: return 0.0m; default: throw new ArgumentException(...); } }ejemplo final
Patrón var 11.2.4
Un var_patterncoincide con cada valor. Es decir, una operación de coincidencia de patrones con una var_pattern siempre se realiza correctamente.
Un var_pattern es aplicable a cada tipo.
var_pattern
: 'var' designation
;
designation
: simple_designation
| tuple_designation
;
tuple_designation
: '(' designations? ')'
;
designations
: designation (',' designation)*
;
Dado un valor de entrada de patrón (§11.1) e, si la designación es discard_designation, denota un descarte (§9.2.9.2) y el valor de e no está enlazado a nada. (Aunque una variable declarada con ese nombre puede estar en el ámbito en ese momento, esa variable con nombre no se ve en este contexto). De lo contrario, si la designación es single_variable_designation, en tiempo de ejecución, el valor de e está enlazado a una variable local recién introducida (§9.2.9) de ese nombre cuyo tipo es el tipo estático de e y el valor de entrada del patrón se asigna a esa variable local.
Se trata de un error si el nombre var se enlazaría a un tipo en el que se usa un var_pattern .
Si la designación es un tuple_designation, el patrón es equivalente a un positional_pattern (§11.2.5) de la (var de formulario, ...
) donde las designacionesson las que se encuentran dentro de la tuple_designation. Por ejemplo, el patrón var (x, (y, z)) es equivalente a (var x, (var y, var z)).
11.2.5 Patrón posicional
Un positional_pattern comprueba que el valor de entrada no nulles , invoca un método adecuado Deconstruct (§12.7) y realiza una coincidencia de patrones adicional en los valores resultantes. También admite una sintaxis de patrón similar a la tupla (sin el tipo proporcionado) cuando el tipo del valor de entrada es el mismo que el tipo que contiene Deconstruct, o si el tipo del valor de entrada es un tipo de tupla, o si el tipo del valor de entrada es object o System.ITuple y el tipo en tiempo de ejecución de la expresión implementa System.ITuple.
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern (',' subpattern)*
;
subpattern
: pattern
| identifier ':' pattern
;
Dada una coincidencia de un valor de entrada con lossubpatrones( de tipo) de patrón, se selecciona un método buscando en tipo las declaraciones accesibles de Deconstruct y seleccionando uno entre ellos con las mismas reglas que para la declaración de deconstrucción.
Se trata de un error si un positional_pattern omite el tipo, tiene un único subpatrón sin un identificador, no tiene property_subpattern y no tiene simple_designation. Esto desambigua entre un constant_pattern entre paréntesis y un positional_pattern.
Para extraer los valores que deben coincidir con los patrones de la lista,
- Si se omite el tipo y el tipo de la expresión de entrada es un tipo de tupla, el número de subpatrones será el mismo que la cardinalidad de la tupla. Cada elemento de tupla coincide con el subpatrón correspondiente y la coincidencia se realiza correctamente si todas estas se realizan correctamente. Si algún subpatrón tiene un identificador, se denominará un elemento de tupla en la posición correspondiente del tipo de tupla.
- De lo contrario, si existe un adecuado
Deconstructcomo miembro de tipo, se trata de un error en tiempo de compilación si el tipo del valor de entrada no es compatible con el patrón con el tipo. En tiempo de ejecución, el valor de entrada se prueba con el tipo . Si se produce un error, se produce un error en la coincidencia de patrones posicionales. Si se ejecuta correctamente, el valor de entrada se convierte en este tipo yDeconstructse invoca con variables generadas por el compilador nuevas para recibir los parámetros de salida. Cada valor que se recibió coincide con el subpatrón correspondiente y la coincidencia se realiza correctamente si todas estas se realizan correctamente. Si algún subpatrón tiene un identificador, se asignará un nombre a un parámetro en la posición correspondiente deDeconstruct. - De lo contrario, si se omite el tipo y el valor de entrada es de tipo
objecto de algún tipo al que se puede convertirSystem.ITuplemediante una conversión de referencia implícita y no aparece ningún identificador entre los subpatrones, la coincidencia usaSystem.ITuple. - De lo contrario, el patrón es un error en tiempo de compilación.
El orden en el que se coinciden los subpatrones en tiempo de ejecución no está especificado y es posible que una coincidencia con errores no intente coincidir con todos los subpatrones.
Ejemplo: aquí, deconstruimos un resultado de expresión y comparamos los valores resultantes con los patrones anidados correspondientes:
static string Classify(Point point) => point switch { (0, 0) => "Origin", (1, 0) => "positive X basis end", (0, 1) => "positive Y basis end", _ => "Just a point", }; public readonly struct Point { public int X { get; } public int Y { get; } public Point(int x, int y) => (X, Y) = (x, y); public void Deconstruct(out int x, out int y) => (x, y) = (X, Y); }ejemplo final
Ejemplo: los nombres de los elementos de tupla y los parámetros Deconstruct se pueden usar en un patrón posicional, como se indica a continuación:
var numbers = new List<int> { 10, 20, 30 }; if (SumAndCount(numbers) is (Sum: var sum, Count: var count)) { Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}"); } static (double Sum, int Count) SumAndCount(IEnumerable<int> numbers) { int sum = 0; int count = 0; foreach (int number in numbers) { sum += number; count++; } return (sum, count); }La salida generada es
Sum of [10 20 30] is 60ejemplo final
11.2.6 Patrón de propiedad
Un property_pattern comprueba que el valor de entrada no nulles y coincide recursivamente con los valores extraídos por el uso de propiedades o campos accesibles.
property_pattern
: type? property_subpattern simple_designation?
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;
Se trata de un error si algún subpatrón de un property_pattern no contiene un identificador.
Es un error en tiempo de compilación si el tipo es un tipo de valor que acepta valores NULL (§8.3.12) o un tipo de referencia que acepta valores NULL (§8.9.3).
Nota: Un patrón de comprobación de valores NULL sale de un patrón de propiedad trivial. Para comprobar si la cadena
sno es NULL, puede escribir cualquiera de los siguientes formularios:#nullable enable string s = "abc"; if (s is object o) ... // o is of type object if (s is string x1) ... // x1 is of type string if (s is {} x2) ... // x2 is of type string if (s is {}) ...nota final
Dada una coincidencia de una expresión e con lossubpatrones{ de tipo} de patrón, se trata de un error en tiempo de compilación si la expresión e no es compatible con el tipo T designado por tipo. Si el tipo está ausente, se supone que el tipo es el tipo estático de e. Cada uno de los identificadores que aparecen en el lado izquierdo de sus subpatrones designará una propiedad o campo legible accesible de T. Si la simple_designation de la property_pattern está presente, declara una variable de patrón de tipo T.
En tiempo de ejecución, la expresión se prueba en T. Si se produce un error, se produce un error en la coincidencia del patrón de propiedad y el resultado es false. Si se ejecuta correctamente, cada property_subpattern campo o propiedad se lee y su valor coincide con su patrón correspondiente. El resultado de toda la coincidencia es false solo si el resultado de cualquiera de estos es false. No se especifica el orden en el que se coinciden los subpatrones y es posible que una coincidencia con errores no pruebe todos los subpatrones en tiempo de ejecución. Si la coincidencia se realiza correctamente y el simple_designation del property_pattern es un single_variable_designation, a la variable declarada se le asigna el valor coincidente.
El property_pattern se puede usar para establecer coincidencias de patrones con tipos anónimos.
Ejemplo:
var o = ...; if (o is string { Length: 5 } s) ...ejemplo final
Ejemplo: se puede agregar una comprobación de tipos en tiempo de ejecución y una declaración de variable a un patrón de propiedad, como se indica a continuación:
Console.WriteLine(TakeFive("Hello, world!")); // output: Hello Console.WriteLine(TakeFive("Hi!")); // output: Hi! Console.WriteLine(TakeFive(new[] { '1', '2', '3', '4', '5', '6', '7' })); // output: 12345 Console.WriteLine(TakeFive(new[] { 'a', 'b', 'c' })); // output: abc static string TakeFive(object input) => input switch { string { Length: >= 5 } s => s.Substring(0, 5), string s => s, ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()), ICollection<char> symbols => new string(symbols.ToArray()), null => throw new ArgumentNullException(nameof(input)), _ => throw new ArgumentException("Not supported input type."), };La salida generada es
Hello Hi! 12345 abcejemplo final
11.2.7 Patrón de descarte
Cada expresión coincide con el patrón de descarte, lo que da como resultado el valor de la expresión que se va a descartar.
discard_pattern
: '_'
;
Se trata de un error en tiempo de compilación para usar un patrón de descarte en un relational_expression del formulario relational_expressionispatrón o como patrón de un switch_label.
Nota: En esos casos, para que coincida con cualquier expresión, use un var_pattern con un descarte
var _. nota final
Ejemplo:
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday)); Console.WriteLine(GetDiscountInPercent(null)); Console.WriteLine(GetDiscountInPercent((DayOfWeek)10)); static decimal GetDiscountInPercent(DayOfWeek? dayOfWeek) => dayOfWeek switch { DayOfWeek.Monday => 0.5m, DayOfWeek.Tuesday => 12.5m, DayOfWeek.Wednesday => 7.5m, DayOfWeek.Thursday => 12.5m, DayOfWeek.Friday => 5.0m, DayOfWeek.Saturday => 2.5m, DayOfWeek.Sunday => 2.0m, _ => 0.0m, };La salida generada es
5.0 0.0 0.0En este caso, se usa un patrón de descarte para controlar
nully cualquier valor entero que no tenga el miembro correspondiente de laDayOfWeekenumeración. Esto garantiza que laswitchexpresión controla todos los valores de entrada posibles. ejemplo final
Patrón de tipo 11.2.8
Se usa un type_pattern para probar que el valor de entrada del patrón (§11.1) tiene un tipo determinado.
type_pattern
: type
;
Un patrón de tipo que asigne un nombre a un tipo T se aplica a cada tipo E para el que E sea compatible con T el patrón (§11.2.2).
El tipo en tiempo de ejecución del valor se prueba con el tipo utilizando las mismas reglas especificadas en el operador is-type (§12.15.12.1). Si la prueba se realiza correctamente, el patrón coincide con ese valor. Es un error en tiempo de compilación si el tipo es un tipo que acepta valores NULL. Este formulario de patrón nunca coincide con un null valor.
11.2.9 Patrón relacional
Un relational_pattern se usa para probar relacionalmente el valor de entrada del patrón (§11.1) con un valor constante.
relational_pattern
: '<' relational_expression
| '<=' relational_expression
| '>' relational_expression
| '>=' relational_expression
;
El relational_expression de un relational_pattern es necesario para evaluar un valor constante.
Los patrones relacionales admiten los operadores <relacionales , <=, >y >= en todos los tipos integrados que admiten estos operadores relacionales binarios con ambos operandos que tienen el mismo tipo: sbyte, , byte, shortushort, , int, uint, floatdoubleulongnuintlongchardecimalninty enumeraciones.
Un relational_pattern se aplica a un tipo T si se define un operador relacional binario integrado adecuado con ambos operandos de tipo T, o si existe una conversión explícita que acepta valores NULL o unboxing desde T hasta el tipo de la expresión constante.
Es un error en tiempo de compilación si la expresión se evalúa como double.NaN, float.NaNo una constante null.
Cuando el valor de entrada tiene un tipo para el que se define un operador relacional binario integrado adecuado, la evaluación de ese operador se toma como el significado del patrón relacional. De lo contrario, el valor de entrada se convierte en el tipo de la expresión constante mediante una conversión explícita que acepta valores NULL o unboxing. Es un error en tiempo de compilación si no existe dicha conversión. El patrón se considera que no coincide si se produce un error en la conversión. Si la conversión se realiza correctamente, el resultado de la operación de coincidencia de patrones es el resultado de evaluar la expresión e «op» v donde e es la entrada convertida, «op» es el operador relacional y v es la expresión constante.
Ejemplo:
Console.WriteLine(Classify(13)); Console.WriteLine(Classify(double.NaN)); Console.WriteLine(Classify(2.4)); static string Classify(double measurement) => measurement switch { < -4.0 => "Too low", > 10.0 => "Too high", double.NaN => "Unknown", _ => "Acceptable", };La salida generada es
Too high Unknown Acceptableejemplo final
11.2.10 Patrón lógico
Un logical_pattern se usa para negar el resultado de una coincidencia de patrón o para combinar los resultados de varias coincidencias de patrones mediante combinación (and) o disjunción (or).
logical_pattern
: disjunctive_pattern
;
disjunctive_pattern
: disjunctive_pattern 'or' conjunctive_pattern
| conjunctive_pattern
;
conjunctive_pattern
: conjunctive_pattern 'and' negated_pattern
| negated_pattern
;
negated_pattern
: 'not' negated_pattern
| primary_pattern
;
not, andy or se denominan colectivamente operadores de patrón.
Un negated_pattern coincide si el patrón que se va a negar no coincide y viceversa. Un conjunctive_pattern requiere que ambos patrones coincidan. Un disjunctive_pattern requiere cualquier patrón que coincida. A diferencia de sus homólogos del operador de lenguaje, && y ||, and y orno son operadores de cortocircuito.
Es un error en tiempo de compilación para que una variable de patrón se declare debajo de un not operador de patrón o or .
Nota: Dado que ni ni
notorpueden producir una asignación definitiva para una variable de patrón, es un error declarar uno en esas posiciones. nota final
En un conjunctive_pattern, el tipo de entrada del segundo patrón se limita mediante los requisitos de restricción de tipos del primer patrón de and. El tipo restringido de un patrón P se define de la siguiente manera:
- Si
Pes un patrón de tipo, el tipo restringido es el tipo del tipo del patrón de tipo. - De lo contrario, si
Pes un patrón de declaración, el tipo restringido es el tipo del tipo del patrón de declaración. - De lo contrario, si
Pes un patrón recursivo que proporciona un tipo explícito, el tipo restringido es ese tipo. - De lo contrario, si
Pcoincide con las reglas deITupleen un positional_pattern (§11.2.5), el tipo restringido es el tipoSystem.ITuple. - De lo contrario, si
Pes un patrón constante en el que la constante no es la constante null y donde la expresión no tiene ninguna conversión de expresión constante al tipo de entrada, el tipo restringido es el tipo de la constante. - De lo contrario, si
Pes un patrón relacional en el que la expresión constante no tiene ninguna conversión de expresión constante al tipo de entrada, el tipo restringido es el tipo de la constante. - De lo contrario, si
Pes unorpatrón, el tipo restringido es el tipo común del tipo restringido de los subpatrones si existe un tipo común. Para ello, el algoritmo de tipo común solo tiene en cuenta las conversiones de identidad, conversión boxing e implícita, y tiene en cuenta todos los subpatrones de una secuencia deorpatrones (ignorando los patrones entre paréntesis). - De lo contrario, si
Pes unandpatrón, el tipo restringido es el tipo restringido del patrón correcto. Además, el tipo restringido del patrón izquierdo es el tipo de entrada del patrón derecho. - De lo contrario, el tipo restringido de es
Pel tipo dePentrada.
Nota: Como se indica en la gramática,
nottiene prioridad sobreand, que tiene prioridad sobreor. Esto se puede indicar o invalidar explícitamente mediante paréntesis. nota final
Cuando aparece un patrón en el lado derecho de is, la extensión del patrón viene determinada por la gramática; como resultado, los operadores andde patrón , ory not dentro del patrón enlazan más estrechamente que los operadores lógicos &&, ||y ! fuera del patrón.
Ejemplo:
Console.WriteLine(Classify(13)); Console.WriteLine(Classify(-100)); Console.WriteLine(Classify(5.7)); static string Classify(double measurement) => measurement switch { < -40.0 => "Too low", >= -40.0 and < 0 => "Low", >= 0 and < 10.0 => "Acceptable", >= 10.0 and < 20.0 => "High", >= 20.0 => "Too high", double.NaN => "Unknown", };La salida generada es
High Too low Acceptableejemplo final
Ejemplo:
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19))); Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9))); Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11))); static string GetCalendarSeason(DateTime date) => date.Month switch { 3 or 4 or 5 => "spring", 6 or 7 or 8 => "summer", 9 or 10 or 11 => "autumn", 12 or 1 or 2 => "winter", _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."), };La salida generada es
winter autumn springejemplo final
Ejemplo:
object msg = "msg"; object obj = 5; bool flag = true; // This is parsed as: (msg is (not int) or string) result = msg is not int or string; Console.WriteLine($"msg (\"msg\"): msg is not int or string: {result}"); // This is parsed as: (obj is (int or string)) && flag bool result = obj is int or string && flag; Console.WriteLine($"obj (5), flag (true): obj is int or string && flag: {result}"); // This is parsed as: (obj is int) || ((obj is string) && flag) result = obj is int || obj is string && flag; Console.WriteLine($"obj (5), flag (true): obj is int || obj is string && flag: {result}"); flag = false; // This is parsed as: (obj is (int or string)) && flag result = obj is int or string && flag; Console.WriteLine($"obj (5), flag (false): obj is int or string && flag: {result}"); // This is parsed as: (obj is int) || ((obj is string) && flag) result = obj is int || obj is string && flag; Console.WriteLine($"obj (5), flag (false): obj is int || obj is string && flag: {result}");La salida generada es
msg ("msg"): msg is not int or string: True obj (5), flag (true): obj is int or string && flag: True obj (5), flag (true): obj is int || obj is string && flag: True obj (5), flag (false): obj is int or string && flag: False obj (5), flag (false): obj is int || obj is string && flag: Trueejemplo final
Subsumpción de patrón 11.3
En una instrucción switch, se trata de un error si el patrón de un caso está subsumado por el conjunto anterior de casos no supervisados (§13.8.3). Informalmente, esto significa que cualquiera de los valores de entrada habría sido coincidente con uno de los casos anteriores. Las reglas siguientes definen cuándo un conjunto de patrones subsume un patrón determinado:
Un patrón Pcoincidiría con una constante K si alguna de las condiciones siguientes contiene:
- la especificación del comportamiento en tiempo de ejecución de ese patrón es que
Pcoincide conK. -
Pes un type_pattern para el tipoTy nonulles yKel tipo en tiempo de ejecución de esTo un tipo derivado deKTo de un tipo que implementaT. -
Pes un relational_pattern con el operador «op» y la constantev, y la expresiónK«op»vse evaluaría comotrue. -
Pes un negated_patternnot P₁yP₁no coincidiría conK. -
Pes un conjunctive_patternP₁ and P₂y ambosP₁coincidiríanKyP₂coincidirían conK. -
Pes un disjunctive_patternP₁ or P₂yP₁coincidiríaKcon oP₂coincidiría conK. -
Pes un discard_pattern.
Un conjunto de patrones Qsubsumes un patrón P si alguna de las condiciones siguientes contiene:
-
Pes un patrón constante y cualquiera de los patrones del conjuntoQcoincidiría conPel valor convertido de . -
Pes un patrón var y el conjunto de patrones es exhaustivo (§11.4) para el tipo del valor de entrada del patrón (Q), y el valor de entrada del patrón no es de un tipo que acepta valores NULL o algún patrón de coincidiría con .Qnull -
Pes un patrón de declaración con tipoTy el conjunto de patronesQes exhaustivo para el tipoT(§11.4). -
Pes un type_pattern para el tipoTy el conjunto de patronesQes exhaustivo para el tipoT. -
Pes un relational_pattern con el operador «op» y el valorvconstante, y para cada valor del tipo de entrada que satisface la relación «op»,valgún patrón del conjuntoQcoincidiría con ese valor. -
Pes un disjunctive_patternP₁ or P₂y el conjunto de subsumesP₁yQsubsumesP₂de patronesQ. -
Pes un conjunctive_patternP₁ and P₂y al menos una de las siguientes suspensiones:QsubsumesP₁oQsubsumesP₂. -
Pes un negated_patternnot P₁yQes exhaustivo para el tipo de entrada considerando solo los valores que no coinciden conP₁. -
Pes un discard_pattern y el conjunto de patronesQes exhaustivo para el tipo del valor de entrada del patrón y el valor de entrada del patrón no es de un tipo que acepta valores NULL o algún patrón enQcoincidiríanullcon . - Algún patrón de es
Qun disjunctive_patternQ₁ or Q₂y reemplazar ese patrón porQ₁enQproduciría un conjunto que subsumesP, o reemplazarlo porQ₂produciría un conjunto que subsumesP. - Algún patrón de
Qes un negated_patternnot Q₁yPno coincidiría con ningún valor queQ₁coincida.
11.4 Exhaustiva de patrones
Informalmente, un conjunto de patrones es exhaustivo para un tipo si, para cada valor posible de ese tipo distinto de NULL, se aplica algún patrón del conjunto. Las reglas siguientes definen cuándo un conjunto de patrones es exhaustivo para un tipo:
Un conjunto de patrones Q es exhaustivo para un tipo T si alguna de las condiciones siguientes contiene:
-
Tes un tipo entero o de enumeración, o una versión que acepta valores NULL de uno de ellos, y para cada valor posible delTtipo subyacente que no acepta valores NULL, algún patrón deQcoincidiría con ese valor; o - Algún patrón de
Qes un patrón var; o - Algún patrón de
Qes un patrón de declaración para el tipoDy hay una conversión de identidad, una conversión de referencia implícita o una conversión boxing deTaD; o - Algunos patrones de
Qes un type_pattern para el tipoDy hay una conversión de identidad, una conversión de referencia implícita o una conversión boxing deTaD; o - Algún patrón de
Qes un discard_pattern; o - Los patrones de
Qincluyen una combinación de relational_patterns y constant_patterncuyos intervalos cubren colectivamente todos los valores posibles delTtipo subyacente que no acepta valores NULL. Parafloatlos tipos ydouble, esto incluyeSystem.Double.NaNoSystem.Single.NaNrespectivamente, ya queNaNno coincide con ningún patrón relacional; o - Algunos patrones de
Qes un disjunctive_patternP₁ or P₂, y reemplazar ese patrón por yP₁P₂enQproduce un conjunto que es exhaustivo paraT; o - Algunos patrones de
Qes una negated_patternnot P₁, y los patrones deQjunto con los valores no coincidentes cubrenP₁todos los valores posibles deT. Un negated_patternnot P₁es exhaustivo por sí mismo cuandoP₁no coincide con ningún valor posible deT; o - Algunos patrones de
Qes un conjunctive_patternP₁ and P₂, y el conjunto que contiene soloP₁es exhaustivo paraTy el conjunto que contiene soloP₂es exhaustivo paraT.
Nota: Cuando un patrón de tipo incluye tipos que aceptan valores NULL, el patrón puede ser exhaustivo para el tipo, pero sigue generando una advertencia porque el patrón de tipo no coincidirá con un
nullvalor. nota final
Nota: Para los tipos de punto flotante, la combinación de patrones
< 0y>= 0no es exhaustiva porque ninguno de los patrones relacionales coincide conNaN. Un conjunto exhaustivo correcto sería< 0,>= 0ydouble.NaN(ofloat.NaN). nota final
Ejemplo:
static void M(byte b) { switch (b) { case 0: case 1: case 2: ... // handle every specific value of byte break; // error: the pattern 'byte other' is subsumed by the (exhaustive) // previous cases case byte other: break; } }ejemplo final
ECMA C# draft specification