1. Introduzione
Già sai scrivere codice così:
switch (color)
{
case "red":
Console.WriteLine("Fermati!");
break;
case "yellow":
Console.WriteLine("Aspetta...");
break;
case "green":
Console.WriteLine("Puoi andare!");
break;
default:
Console.WriteLine("Che colore è questo?");
break;
}
Ma che succede se vogliamo assegnare un valore diverso a una variabile in base al parametro di input, tipo restituire una stringa da una funzione in base a un numero? Prima delle switch-espressioni dovevi scrivere robe tipo questa:
string meaning;
switch (number)
{
case 42:
meaning = "Risposta alla domanda fondamentale sulla vita, l'universo e tutto quanto";
break;
case 7:
meaning = "Numero fortunato";
break;
default:
meaning = "Numero normale";
break;
}
Non è proprio elegante per un linguaggio del XXI secolo, vero? Vorresti restituire subito il valore, come si fa di solito nei linguaggi funzionali.
Ed è qui che entrano in gioco le switch-espressioni — una delle feature più belle (e fresche) di C#, a partire dalla versione 8.0.
2. switch-espressioni: sintassi che ti viene voglia di abbracciare
Confrontiamo: statement e espressione
Il classico switch è uno statement ("istruzione"), mentre la switch-espressione è una expression, cioè calcola un valore che puoi subito assegnare a una variabile o restituire da un metodo.
Struttura di una switch-espressione:
var result = value switch
{
pattern1 => expression1,
pattern2 => expression2,
_ => defaultExpression // "underscore" - cioè "altrimenti"
};
Per esempio:
int number = 42;
string meaning = number switch
{
42 => "Risposta alla domanda fondamentale sulla vita, l'universo e tutto quanto",
7 => "Numero fortunato",
_ => "Numero normale"
};
Console.WriteLine(meaning); // => Risposta alla domanda fondamentale sulla vita, l'universo e tutto quanto
Tutto compatto, leggibile, niente codice chilometrico, neanche un break;.
Nota bene: l’underscore _ — serve per "prendere tutti gli altri casi", è l’analogo di default.
3. switch-espressioni e pattern: come si combinano
Qui inizia il vero divertimento. Nelle switch-espressioni puoi usare non solo valori normali, ma anche pattern: controlli su range, tipo, proprietà degli oggetti, deconstruction (spezzare un oggetto nelle sue parti), e pure combinatorial patterns (and, or, not).
Esempi di pattern nelle switch-espressioni
Pattern costanti
È quello che abbiamo già fatto sopra: confronto con 42, 7 e così via.
Range e confronti
int age = 17;
string category = age switch
{
< 18 => "Minorenne",
>= 18 and <= 65 => "Adulto",
> 65 => "Anziano",
_ => "Categoria d'età sconosciuta"
};
Console.WriteLine(category);
Tra l’altro, nota che puoi usare più condizioni insieme! C# sta diventando sempre più espressivo.
Pattern di tipo (Type Patterns)
Mettiamo che hai un oggetto che può essere di tipo diverso (tipo object value;). Puoi gestire i vari tipi così:
object value = 3.14;
string description = value switch
{
int i => $"Numero intero: {i}",
double d => $"Numero decimale: {d:F2}",
string s => $"Questa è una stringa: '{s}'",
null => "null!",
_ => "Qualcos'altro"
};
Console.WriteLine(description); // => Numero decimale: 3.14
Pattern sulle proprietà (Property Patterns e Positional Patterns)
Da C# 8 in poi puoi controllare i valori delle proprietà direttamente nella switch-espressione.
Esempio con oggetto
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
User user = new User { Name = "Anna", Age = 17 };
string welcome = user switch
{
{ Age: < 18 } => $"Ciao, {user.Name}! Sei un adolescente.",
{ Age: >= 18 and <= 65 } => $"Ehi, {user.Name}! La vita adulta è fantastica.",
{ Age: > 65 } => $"Benvenuto, {user.Name}! Sei sempre il benvenuto.",
_ => "Età sconosciuta"
};
Console.WriteLine(welcome);
Qui tra le parentesi graffe { Age: < 18 } — è un property pattern, cioè controlli solo una proprietà dell’oggetto.
4. Nuovi pattern C# 11-14
C# punta a essere compatto e flessibile. Di recente sono arrivati i combinatorial patterns: and, or, not, e sono migliorati anche i positional patterns. Vediamoli insieme.
Pattern logici: and, or, not
Puoi comporre condizioni complesse, proprio come nella logica matematica!
int temperature = 25;
string result = temperature switch
{
< 0 => "Gelo!",
>= 0 and < 20 => "Fresco",
>= 20 and < 30 => "Confortevole",
>= 30 or <= -30 => "Estremo!",
_ => "Temperatura strana"
};
Se vuoi escludere dei casi, nessun problema:
int score = 80;
string grade = score switch
{
>= 90 => "Ottimo",
>= 60 and not >= 90 => "Buono",
_ => "Scarso"
};
Deconstruction (Positional Patterns)
Se hai una struct o un record che supporta la deconstruction, C# ti permette di spezzare l’oggetto direttamente nella switch-espressione:
public record Point(int X, int Y);
Point p = new Point(10, 20);
string desc = p switch
{
(0, 0) => "Origine degli assi",
(var x, 0) => $"Sull'asse X, X={x}",
(0, var y) => $"Sull'asse Y, Y={y}",
(var x, var y) when x == y => $"Sulla diagonale: {x}",
_ => $"Nel punto ({p.X}, {p.Y})"
};
Console.WriteLine(desc); // => Nel punto (10, 20)
5. Quando e perché usare le switch-espressioni
Nel C# moderno le switch-espressioni non sono solo una "feature cool", ma un vero modo per evitare codice prolisso, rendere il codice più compatto, facile da testare e mantenere. È fondamentale quando scrivi parser, handler di comandi, logica di business, regole di configurazione — ovunque ti serva ramificare l’esecuzione su criteri complessi, non solo su valori ma anche su tipi, range, proprietà, combinazioni.
Ai colloqui
- Come gestiresti le diverse risposte di un utente?
- Come faresti a restituire un valore diverso da una funzione, in base sia al tipo che al valore?
- Come aggiungeresti nuove regole senza mille if-else?
Mostra una switch-espressione con i pattern! Così dimostri subito che conosci le nuove feature del linguaggio e hai uno stile di coding moderno.
Tabella: confronto tra switch-statement e switch-espressione
| Caratteristica | switch statement | switch expression |
|---|---|---|
| Tipo | statement (istruzione) | expression (espressione) |
| Uso di break | obbligatorio | non serve |
| Può restituire un valore | solo tramite variabile | sì, restituisce direttamente |
| Può usare pattern | parzialmente | completamente (type, property, ecc.) |
| Trappola | puoi dimenticare break | tutti i rami devono restituire un valore |
6. Errori tipici e piccole trappole
- Chi inizia spesso si confonde tra switch-statement ("statement") e switch-espressione ("expression"). Per esempio, dimentica che nella switch-espressione non servono break; e che tutti i rami devono restituire un valore.
- Se dimentichi il ramo _, il compilatore ti avvisa: "e se non corrisponde niente?".
- Nella switch-espressione non puoi usare goto (e meno male!).
- Se duplichi una condizione (tipo due pattern uguali), il compilatore non te la fa passare.
- Occhio al tipo di valore restituito dalla switch-espressione: deve essere compatibile con la variabile a cui lo assegni.
GO TO FULL VERSION