Para ponernos en situación, imaginemos que tenemos una expresión como la siguiente, donde retornamos el texto
"Rojo"
cuando le suministramos el valor de enumeración Color.Red
, y "Desconocido"
en otros casos. Algo fácil de solucionar utilizando el operador condicional ?
:enum Color { Purple, Red, Blue, Orange, Black, Pink, Gray, Green, White };
string GetColorName(Color color)
{
var str = color == Color.Red ? "Rojo" : "Desconocido";
return str;
}
Imaginemos ahora que la aplicación evoluciona y debemos añadir otro caso a esta condición, como el soporte para el color azul. No pasa nada, podemos seguir el mismo patrón, aunque empezaremos a notar que esto no va a escalar demasiado porque la legibilidad empieza a resentirse:var str = color == Color.Red ? "Rojo" : color == Color.Blue ? "Azul" : "Desconocido";
Podemos suponer cómo acabará esto cuando el número de casos a contemplar comiencen a dispararse. Seguro que todos tenemos código como el siguiente, donde ya cuesta trabajo ver qué casos han sido implementados y, si son correctos:
var str = color == Color.Red ? "Rojo" : color == Color.Blue ? "Azul" :
color == Color.Orange? "Naranja": color == Color.Purple? "Púrpura":
color == Color.Black? "Negro": color == Color.Green? "Verde":
color == Color.Purple? "Violeta": color == Color.Gray? "Gris":
color == Color.Pink? "Rosa": color == Color.White? "Blanco": "Desconocido";
Es cierto que hasta el momento teníamos soluciones más o menos razonables al problema. Por ejemplo, podríamos formatear el código para que quede más legible poniendo cada condición en una línea. Con esto solucionaríamos el problema de la legibilidad, pero no podríamos verificar su corrección, algo difícil de hacer a ojo si se trata de un buen número de opciones.Fijaos que en el código anterior hemos repetido deliberadamente el caso Color.Purple
. Es fácil pasar por alto este error cuando el código es extenso.
Por supuesto, podríamos considerar el uso de opciones más artesanas, como la implementación mediante diccionarios o similares, pero resultarían algo verbosas y no impedirían la duplicación de valores:var dic = new Dictionary<Color, string>()
{
[Color.Red] = "Rojo",
[Color.Blue] = "Azul",
[Color.Orange] = "Naranja",
[Color.Purple] = "Púrpura",
[Color.Black] = "Negro",
[Color.Green] = "Verde",
[Color.Gray] = "Gris",
[Color.Purple] = "Violeta",
...
};
if (!dic.TryGetValue(color, out string result))
result = "Desconocido";
Pero lo más razonable sería refactorizar a un bloque switch
. En este caso podríamos asegurar que no cometemos los errores de antes, pero a cambio tendríamos que introducir bastante código, lo cual incidiría negativamente en la legibilidad:string result;
switch(color)
{
case Color.Red:
result = "Rojo";
break;
case Color.Blue:
result = "Azul";
break;
case Color.Orange:
result = "Naranja";
break;
case Color.Purple:
result = "Púrpura";
break;
...
default:
result = "Desconocido";
break;
}
Pues bien, en este punto es donde entran las expresiones switch de C# 8, que nos permiten implementar una mezcla con lo mejor de las opciones anteriores: la inmediatez del operador condicional ?
con la potencia del switch
:var str = color switch
{
Color.Red => "Rojo",
Color.Blue => "Azul",
Color.Orange => "Naranja",
Color.Purple => "Púrpura",
Color.Black => "Negro",
Color.Green => "Verde",
Color.Gray => "Gris",
Color.Pink=> "Rosa",
_ => "Desconocido"
};
Observad que sintácticamente recuerda algo a los bloques switch
de toda la vida, pero tiene algunas diferencias importantes:- La variable objeto de la condición aparece antes de la palabra clave
switch
. - Se usa "=>" para determinar el retorno en cada caso.
- Cada opción se resuelve en una expresión, no hay bloques de código ni
break
para distinguirlas. - El caso
default
se implementa también de forma más concisa, con el carácter de descarte "_".
switch
, es posible utilizar toda la potencia que últimamente se ha dado a este tipo de construcciones con pattern matching para implementar escenarios más complejos:object obj = GetSomething();
Console.WriteLine(obj switch
{
Color color when color == Color.Red => "Rojo",
Color color => color.ToString(),
string str => str,
int i => i.ToString("#,##0")
});
Publicado en: www.variablenotfound.com.