C# 9.0 – Specification – Pattern Matching Enhancements
Índice general – C# 9.0 – Specification
Introducción
Pattern Matching no es algo nuevo dentro de C# como lenguaje, de hecho, se empezó a emplear en C# 6, y a lo largo de los siguientes años y diferentes especificaciones del lenguaje C#, se ha ido completando, ampliando y mejorando cada vez.
Sobre ello hablé en 2017 (C# 7.0 – Specification – Pattern Matching), y en 2019 sobre C# 8.0 (Pattern Matching – Switch Expressions, Pattern Matching – Property Patterns, Pattern Matching – Tuple Patterns y Pattern Matching – Positional Patterns).
Ahora bien, ¿qué nos ofrece Pattern Matching en C# 9?.
Eso es lo que veremos a continuación.
Pattern Matching en Switch Expressions
Antes de empezar, deberemos hacer una parada rápida para hablar de sintáxis o instrucciones switch y expresiones switch.
Una instrucción switch es una declaración de selección que permite seleccionar una sección entre varias posibilidades. Para seleccionar la sección a ejecutar, se basa en la coincidencia o búsqueda de un patrón de la expresión de coincidencia.
Un sencillo ejemplo de una instrucción switch que todos conocemos sería por ejemplo:
using System; public class MyClass { public static void Main() { var input = "green"; var output = String.Empty; switch (input) { case "red": output = "Red color!"; break; case "green": output = "Green color!"; break; case "blue": output = "Blue color!"; break; default: output = "Other"; break; }; Console.WriteLine(output); } }
Las expresiones switch por su parte, fueron introducidas en C# 8, y se basa principalmente en que dentro de un switch es posible utilizar un operador de asignación. Dicho de otro modo, es el uso de switch cómo patrón de expresión.
Un ejemplo de aplicación de una expresión switch sería por ejemplo el siguiente código:
using System; public class MyClass { public static void Main() { var input = "green"; var output = String.Empty; output = input switch { "red" => "Red color!", "green" => "Green color!", "blue" => "Blue color!", _ => "Other color!" }; Console.WriteLine(output); } }
Switch Expressions en C# 8 y C# 9
Aunque ya hemos visto un ejemplo de switch expressions en C# 8, vamos a ver otro para explicar a través de él, lo que trae de nuevo en C# 9.
Partiremos del siguiente código fuente de una switch expression en C# 8:
using System; public class MyClass { public static void Main() { var person = new Person { Name = "John", Age = 17 }; string CheckAge(object hero) => hero switch { Person p when p.Age < 18 => "Adolescente", Person p when p.Age > 17 && p.Age <= 65 => "Trabajador", Person _ => "Jubilado", _ => "Unknown" }; Console.WriteLine(CheckAge(person)); } public class Person { public string Name { get; set; } public int Age { get; set; } } }
En este código, tenemos una switch expression que evalúa el objeto Person, y dentro del mismo, el valor de Age.
De acuerdo a ese valor, obtendremos un resultado, e incluso si valiera null el objeto, devolvería en este caso el valor Unknown.
Este ejemplo funcional en C# 8, puede quedar realmente simplificado en C# 9.
Démonos cuenta que lo que estamos evaluando en la expresión swith del ejemplo anterior es la edad (Age).
Así que el código simplificado en C# 9 podría quedar de la siguiente forma:
using System; public class MyClass { public static void Main() { var person = new Person { Name = "John", Age = 17 }; string CheckAge(Person person) => person.Age switch { < 18 => "Adolescente", > 17 and <= 65 => "Trabajador", _ => "Jubilado" }; Console.WriteLine(CheckAge(person)); } public class Person { public string Name { get; set; } public int Age { get; set; } } }
En este código, un par de apuntes.
¿Qué ocurre si person lo declaramos como null?. Pues básicamente dará un error. Concretamente una excepción de tipo NullReferenceException.
Otra característica interesante es el uso del operador lógico and a la hora de combinar en este caso un rango de valores. Podríamos combinar o usar operadores and, or y not.
El uso de operadores lógicos, facilita la lectura del código siempre.
De hecho, con esta característica del lenguaje, podríamos preguntar de forma más natural sobre si nuestro objeto es null o no.
Por ejemplo de esta forma:
using System; public class MyClass { public static void Main() { var person = null; if (person is not null) Console.WriteLine($"{person.Name} is {person.Age} years old!"); else Console.WriteLine("person is unknown"); } public class Person { public string Name { get; set; } public int Age { get; set; } } }
Aquí utilizamos además de not, is, pudiendo escribir algo como:
if (person.Age is > 0 and <= 17) Console.WriteLine("Adolescente");
Como podemos observar, el pattern matching es posiblemente una característica de lenguaje de C# bastante potente que nos puede ahorrar mucho código al mismo tiempo que nos ofrece cierta «potencia», flexibilidad y legibilidad dentro de la evaluación de una expresión y dentro del código que lo usa.
Happy Coding!