Menú de navegaciónMenú
Categorías

La mejor forma de Aprender Programación online y en español www.campusmvp.es

?id=dddef6b9-62e1-4f10-884b-d11b3cba3144

C#: Condicionales más simples usando coincidencia de patrones de objetos

Normalmente cuando queremos verificar que un objeto cumple con ciertas propiedades utilizamos un condicional escribiendo una y otra vez el objeto para poder hacer la comprobación.

Por ejemplo, en este código hemos definido una clase simple llamada Person e instanciamos un objeto de la misma:

class Person
{
    public string Name { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

List<Person> personitas = new List<Person>();
	personitas.Add(new Person { Name = "Juan", LastName = "Perez", Age = 20 });
	personitas.Add(new Person { Name = "Elvira", LastName = "García", Age = 24});
	personitas.Add(new Person { Name = "Pedro", LastName = "González", Age = 30});
	personitas.Add(new Person { Name = "Maria", LastName = "", Age = 40});
	personitas.Add(new Person { Name = "José Antonio", LastName = "Español", Age = 50 });

Si ahora quisiéramos sacar una lista con las personas que cumplan con ciertas condiciones, por ejemplo que tengan entre 20 y 40 años y que tengan apellidos haríamos un condicional parecido a este:

List<Person> personitas1 = new List<Person>();
foreach (Person p in personitas)
{
    if (p.Age >= 20 && p.Age <= 40 && p.LastName.Length > 0)
        personitas1.Add(p);
}
Console.WriteLine(personitas1);

No está mal, pero es un poco tedioso escribir todo eso.

Podemos simplificarlo si usamos el método extensor FindAll de Linq aplicándolo a la lista, que toma una expresión lambda para decidir qué elementos encuentra y filtra:

List<Person> personitas1 = personitas.FindAll(p => p.Age >= 20 && p.Age <= 40 && p.LastName.Length > 0);

Aún así demasiado largo.

Podemos simplificarlo gracias a la coincidencia de patrones de C#, que está disponible a partir dela versión 7 del lenguaje y que usa el operador is. Estas expresiones nos permiten comparar un objeto con un patrón para el mismo, siendo más cortos, más claros y ahorrándonos escribir innecesariamente.

Se trata de definir cómo queremos que sea el objeto con el que queremos compararnos, por ejemplo así:

List<Person> personitas1 = personitas.FindAll(p => p is { 
                                                            Age: >= 20, 
                                                            Age: <= 40, 
                                                            LastName.Length: >0
                                                        });

De hecho, lo podemos simplificar usando operadores simples como and, or o not en la expresión de cada propiedad:

List<Person> personitas1 = personitas.FindAll(p => p is 
                                              { 
                                                  Age: >= 20 and <= 40, 
                                                  LastName.Length: >0
                                              });

Esto está muy bien, pero tiene algunas limitaciones, y es que solo podemos emplear constantes para los valores y, además, sólo podemos usar las propiedades y las propiedades de éstas, pero no sus métodos. Así, por ejemplo, si quisiésemos filtrar de este modo a aquellas personas cuyo apellido termine en "ez", nos daría un error:

List<Person> personitas1 = personitas.FindAll(p => p is 
												{
													Age: >=20 and <=40, 
													LastName.Length: > 0,
													p.LastName.EndsWith("ez"): true
												});

¡Esto no es válido!

Tendríamos que combinar la coincidencia de patrones con una condición convencional:

List<Person> personitas1 = personitas.FindAll(p => p is { 
                                                            //Age: >= 20, 
                                                            //Age: <= 40, 
                                                            Age: >= 20 and <= 40,
                                                            LastName.Length: >0
                                                        }
                                                        && 
                                                        p.LastName.EndsWith("ez"));

También podemos utilizar propiedades complejas en la coincidencia de patrones. Por ejemplo, supongamos que le añadimos una propiedad Manager de tipo Person para saber de quién dependen en una organización:

class Person
{
    public string Name { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
	public Person Manager;
}

List<Person> personitas = new List<Person>();
	personitas.Add(new Person { Name = "Juan", LastName = "Perez", Age = 20 });
	personitas.Add(new Person { Name = "Elvira", LastName = "García", Age = 24, Manager = personitas[0] });
	personitas.Add(new Person { Name = "Pedro", LastName = "González", Age = 30, Manager = personitas[0] });
	personitas.Add(new Person { Name = "Maria", LastName = "", Age = 40, Manager = personitas[1] });
	personitas.Add(new Person { Name = "José Antonio", LastName = "Español", Age = 50 });

Ahora podríamos hacer filtros como estos:

List<Person> personitas3 = personitas.FindAll(p => p is {
						Manager.LastName: "Perez"
					 });
Console.WriteLine(personitas3);

Pero mucho cuidado con esto ya que tiene sus limitaciones:

  • Como ya he dicho antes, solo se permiten constantes o literales en el patrón, así que esto daría un error de sintaxis:
string lnManager = "Perez"
List<Person> personitas3 = personitas.FindAll(p => p is {
    Manager.LastName: lnManager
});

Obteniendo un error ya en tiempo de edición:

Error que indica que se espera un valor constante y no una variable

  • Lo de usar propiedades de las propiedades en la expresión sólo funciona con C# 10 o posterior, o sea, con .NET 6 o posterior. Si lo intentamos con una versión más antigua nos dará un error, pero podemos saltarnos la limitación anidando la coincidencia de patrones, así:
List<Person> personitas3 = personitas.FindAll(p => p is {
						Manager: {LastName: "Perez"}
					 });
Console.WriteLine(personitas3);

En resumen

La coincidencia de patrones para propiedades de objetos es una técnica muy útil para ciertos casos que nos permite ahorrar tiempo y mejorar la claridad de lo que estamos haciendo. Aprende a sacarles partido y a utilizarlos en tu código a partir de ahora.

Y si quieres aprenden C# y .NET en serio y no "con alfileres" para no perderte cosas importantes como estas y ser un buen profesional, deberías estudiar con nuestro curso de la Desarrollo con la plataforma .NET y C#

¡No te arrepentirás!

Fecha de publicación:
José Manuel Alarcón Fundador de campusMVP, es ingeniero industrial y especialista en consultoría de empresa. Ha escrito diversos libros, habiendo publicado hasta la fecha cientos de artículos sobre informática e ingeniería en publicaciones especializadas. Microsoft lo ha reconocido como MVP (Most Valuable Professional) en desarrollo web desde el año 2004 hasta la actualidad. Puedes seguirlo en Twitter en @jm_alarcon o leer sus blog técnico o personal. Ver todos los posts de José Manuel Alarcón
Archivado en: Lenguajes y plataformas

Boletín campusMVP.es

Solo cosas útiles. Una vez al mes.

🚀 Únete a miles de desarrolladores

DATE DE ALTA

x No me interesa | x Ya soy suscriptor

La mejor formación online para desarrolladores como tú

Agregar comentario

Los datos anteriores se utilizarán exclusivamente para permitirte hacer el comentario y, si lo seleccionas, notificarte de nuevos comentarios en este artículo, pero no se procesarán ni se utilizarán para ningún otro propósito. Lee nuestra política de privacidad.