Pattern matching in C#: scenari avanzati che probabilmente non conosci
Il pattern matching in C# non è solo un modo più elegante di scrivere condizioni: è un cambio di paradigma nel modo in cui si ragiona sulla struttura dei dati. A partire da C# 7 e con evoluzioni significative nelle versioni successive, il pattern matching è diventato uno strumento potentissimo per scrivere codice più leggibile, manutenibile e talvolta anche più efficiente.
In questo articolo esploreremo i pattern avanzati che molti sviluppatori .NET tendono a ignorare o a sottoutilizzare, partendo da un progetto concreto che dimostra ogni scenario.
Setup del progetto di esempio
Prima di tutto, creiamo un’applicazione console di test:
dotnet new console -n PatternMatchingDemo
cd PatternMatchingDemo
Definiamo i modelli come record, ideali per il pattern matching grazie alla loro natura value-based:
namespace PatternMatchingDemo.Records;
public record Address(string City, string Country);
public record User(string Name, int Age, Address Address, List<string> Roles);
public record Request(string Source, int Priority);
public record Point(int X, int Y);
E popoliamo alcune collezioni di test:
var users = new List<User>
{
new("Ali", 25, new Address("Milano", "Italy"), new List<string> { "Admin", "User" }),
new("Sara", 17, new Address("Roma", "Italy"), new List<string> { "User" }),
new("Kennedy", 65, new Address("London", "UK"), new List<string> { "Guest" })
};
var requests = new List<Request>
{
new("System", 10),
new("User", 3),
new("System", 2)
};
Property Pattern: matching annidato
Uno dei pattern più utili è il property pattern, che permette di verificare le proprietà di un oggetto direttamente nell’espressione di matching, incluse proprietà annidate:
foreach (var user in users)
{
if (user is { Address.City: "Milano" })
{
Console.WriteLine($"{user.Name} è di Milano");
}
}
Il confronto tradizionale richiederebbe:
if (user != null && user.Address != null && user.Address.City == "Milano")
La versione con property pattern è non solo più compatta, ma anche null-safe per definizione: se user o user.Address sono null, il pattern semplicemente non matcha.
Pattern con not: negazione elegante
foreach (var user in users)
{
if (user is not { Address.City: "Milano" })
{
Console.WriteLine($"{user.Name} non è di Milano");
}
}
Il keyword not inverte il risultato del pattern, rendendo esplicito il significato senza bisogno di operatori logici aggiuntivi.
Matching su casi multipli con or
foreach (var user in users)
{
if (user is { Address.City: "Milano" or "Roma" })
{
Console.WriteLine($"{user.Name} vive in una grande città italiana");
}
}
Il combinatore or all’interno di un pattern è molto più leggibile di una serie di condizioni concatenate con ||, specialmente quando le condizioni riguardano la stessa proprietà.
Pattern Matching dentro LINQ
Il pattern matching si integra perfettamente con LINQ, permettendo query molto espressive:
var adultiItaliani = users
.Where(u => u is { Age: > 18, Address.Country: "Italy" })
.ToList();
foreach (var user in adultiItaliani)
{
Console.WriteLine($"{user.Name} è un adulto italiano");
}
Questa combinazione è particolarmente potente per filtrare DTO complessi, validare oggetti di dominio o implementare query su collezioni in memoria.
Pattern relazionali e logici
I pattern relazionali (>, <, >=, <=) combinati con i pattern logici (and, or) permettono di esprimere range e condizioni composite in modo molto naturale:
foreach (var user in users)
{
if (user.Age is > 18 and < 60)
{
Console.WriteLine($"{user.Name} è un adulto lavorativo");
}
else if (user.Age is < 18 or > 60)
{
Console.WriteLine($"{user.Name} appartiene a una categoria di età speciale");
}
}
Switch Expression
La switch expression (introdotta in C# 8) è una versione compatta e restituisce un valore. Elimina la verbosità del tradizionale switch statement:
foreach (var user in users)
{
var categoria = user.Age switch
{
< 13 => "Bambino",
< 20 => "Adolescente",
< 60 => "Adulto",
_ => "Senior"
};
Console.WriteLine($"{user.Name} => {categoria}");
}
Rispetto allo switch classico, la versione expression è più concisa, obbliga a coprire tutti i casi (o aggiungere il wildcard _) e restituisce direttamente un valore senza variabili intermedie.
Pattern Type + Condition
Il pattern di tipo permette di verificare il tipo di un oggetto e aggiungere una condizione contemporaneamente:
object value = 150;
// Modo tradizionale
if (value is int number && number > 100)
{
Console.WriteLine("Numero grande (vecchio stile)");
}
// Con pattern matching
if (value is int and > 100)
{
Console.WriteLine("Numero grande (pattern matching)");
}
Questo è particolarmente utile quando si lavora con object, dynamic, o con gerarchie di tipi complesse.
List Pattern (C# 11+)
Introdotto in C# 11, il list pattern consente di matchare la struttura e il contenuto di array e liste:
int[] nums = { 1, 2, 3 };
if (nums is [1, 2, 3])
{
Console.WriteLine("Match esatto");
}
if (nums is [1, .., 3])
{
Console.WriteLine("Inizia con 1 e finisce con 3");
}
if (nums is [_, _, _])
{
Console.WriteLine("Array con esattamente 3 elementi");
}
Il slice pattern .. è molto flessibile: può matchare zero o più elementi nel mezzo di una sequenza. Questo pattern è molto utile per validare payload di API che arrivano come array, controllare header HTTP, o verificare strutture di dati fisse.
Positional Pattern
var point = new Point(10, 20);
if (point is (10, 20))
{
Console.WriteLine("Il punto è (10,20)");
}
// Con switch expression
var descrizione = point switch
{
(0, 0) => "Origine",
(_, 0) => "Sull'asse X",
(0, _) => "Sull'asse Y",
_ => $"Punto generico ({point.X},{point.Y})"
};
Console.WriteLine(descrizione);
Il positional pattern decostruisce l’oggetto usando il metodo Deconstruct (disponibile automaticamente per i record) e permette di matchare ogni componente individualmente.
Combined Pattern: la vera potenza
Combinare più pattern insieme permette di esprimere logica di business complessa in modo dichiarativo:
foreach (var user in users)
{
if (user is
{
Age: > 18,
Address.Country: "Italy",
Roles: ["Admin", ..]
})
{
Console.WriteLine($"{user.Name} è un admin adulto italiano");
}
}
Questo esempio combina property pattern annidato, relational pattern e list pattern in un’unica espressione. In scenari reali, questa tecnica è applicabile per authorization checks, validazione di DTO, o routing di request handler.
Null Pattern
User? maybeUser = null;
if (maybeUser is not null)
{
Console.WriteLine("L'utente esiste");
}
else
{
Console.WriteLine("L'utente è null");
}
Il null pattern con is not null è semanticamente più preciso di != null in contesti di nullable reference types, ed è la forma raccomandata nelle linee guida di C# moderno.
Guard Clause nelle switch expression
int number = 7;
var result = number switch
{
int n when n % 2 == 0 => "Pari",
int n when n % 2 != 0 => "Dispari",
_ => "Sconosciuto"
};
Console.WriteLine(result);
La clausola when aggiunge una condizione aggiuntiva a un pattern. Utile quando il solo pattern non è sufficiente a discriminare i casi.
Request Handling pattern
Un esempio pratico di uso combinato in un sistema di routing delle request:
foreach (var request in requests)
{
var response = request switch
{
{ Source: "System", Priority: > 5 } => "Richiesta di sistema critica",
{ Source: "User", Priority: <= 5 } => "Richiesta utente normale",
_ => "Fallback generico"
};
Console.WriteLine($"{request.Source} ({request.Priority}) => {response}");
}
Questo schema è applicabile in moltissimi contesti: event sourcing, command dispatcher, middleware pipeline, validazione di business rules.
Considerazioni sulle performance
Oltre alla leggibilità, il pattern matching in C# è progettato per essere efficiente. Il compilatore ottimizza le switch expression in jump table o sequenze di confronto ottimizzate. Per tipi primitivi, le performance sono equivalenti o superiori a catene di if-else.
Per scenari di alta performance con molti branch (es. parser, protocol handler), vale la pena misurare con BenchmarkDotNet, ma nella stragrande maggioranza dei casi applicativi il pattern matching non introduce overhead significativo.
Conclusione
Il pattern matching in C# è uno strumento che va ben oltre il semplice is o lo switch. Combinando property pattern, list pattern, relational pattern e switch expression, è possibile scrivere logica complessa in modo dichiarativo e leggibile.
La chiave per sfruttarlo al meglio è conoscere tutti i tipi di pattern disponibili e riconoscere le situazioni in cui possono sostituire costrutti più verbosi. Un codice che legge come il problema che risolve è un codice di qualità superiore.
Il codice sorgente di esempio è disponibile su GitHub: github.com/elmahio-blog/Patter…
Fonte originale: Pattern matching in C#: Advanced scenarios you didn’t know — elmah.io Blog
Gabriele Primavera
in reply to Gabriele Primavera • • •Il manifesto del vivaio 🌱
> Il Vivaio Collettivo Lecciofante è un spazio comune pensato per ospitare piccoli alberi (<2+ anni) destinati a progetti locali di riforestazione, avvicinamento della frutta ai cittadini e altri servizi ecosistemici a beneficio della comunità.
> Nasce dalla volontà di un gruppo di "pastori di alberi" legati al gruppo di Guerrilla Gardening "Lecciofanti", operante su Pisa di unire le forze per aumentare la propria entropia verde
(1/3)
reshared this
rag. Gustavino Bevilacqua, Rouge e Gilberto Ficara reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •> , e magari alleviare lo sforzo individuale di dover innaffiare alberi ognuno a casa propria.
> Per il momento, la superficie disponibile è limitata a ~25m², ma ipotizziamo di allargarci ed, eventualmente, creare una sorta di "vivaio diffuso", perché crediamo fermamente che le nostre città debbano essere sostanzialmente più verdi e che sia un imperativo aumentare la disponibilità di frutta - quindi di pubblica salute e solidarietà - ai consumatori che risiedono in città;
(2/3)
reshared this
rag. Gustavino Bevilacqua reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •> non già creando zone dedicate e centralizzate, ma creando una rete diffusa e facilmente accessibile da tutti con una breve camminata.
(3/3)
Aiutateci a iniziare questo bellissimo progetto, soprattutto in un momento come questo, dove il Monte Pisano sta ancora bruciando!
reshared this
rag. Gustavino Bevilacqua reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •Stanno già arrivando le prime donazioni per il #mastoBosco! 🌳💰 Grazie a tutti!
Grazie a chi condividerà il messaggio originale, aiutandoci a creare una base per piantare centinaia di alberi l'anno!
Potete donare anche voi da qui! paypal.com/pools/c/9oPd2FIm3S
Per chi ha già donato, invece, ricordate che avete diritto a ricevere subito dei semi dalla nostra selezione, compilando questo form! 🌱
framaforms.org/mastobosco-un-v…
MastoBosco! Un piccolo vivaio per Pisa.
www.paypal.comreshared this
rag. Gustavino Bevilacqua, Il Gufo., Micolcosta, Oblomov e Rachele 🌚 reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •Siamo arrivato a 40€, ma la strada è ancora lunga! Aiutateci a piantare centinaia di albero nel nostro vivaio collettivo!
Il rimo traguardo è intorno ai 55€, quando potremo permetterci il rubinetto elettrico a due vie per fare la distribuzione dell'acqua.
Senza contare 18€ di batteria ricaricabile da 9V 😅
reshared this
rag. Gustavino Bevilacqua, Oblomov, Vespa cartolaia e Micolcosta reshared this.
thomaso
in reply to Gabriele Primavera • • •Gabriele Primavera
in reply to thomaso • • •Grazie mille @thomaso! Siamo un gruppo di appassionati e si fa quel che si può, cercando sempre di crescere 😊
Purtroppo non ho satispay... Ti da problemi anche con un trasferimento diretto? paypal.me/gabrieleprimavera (scrivilo nelle note così sposto nella cassa del Vivaio 😊)
Payez Gabriele Primavera avec PayPal.Me
PayPal.Methomaso
in reply to Gabriele Primavera • • •Gabriele Primavera
in reply to thomaso • • •Grazie mille @thomaso per la donazione per il #mastoBosco! 🌳
Ricorda che, se vuoi, puoi richiedere una consegna di semi dalla nostra collezione direttamente a casa da questo form!
framaforms.org/mastobosco-un-v…
MastoBosco? Un vivaio collettivo per Pisa! | Framaforms.org
framaforms.orgMicolcosta
in reply to Gabriele Primavera • • •Gabriele Primavera
in reply to Micolcosta • • •Gabriele Primavera
in reply to Gabriele Primavera • • •Andiamo per i 100€ per il #mastoBosco! 🌳🌳🌳
Con questi ci possiamo permettere il rubinetto elettrico per la distribuzione per l'acqua e il galleggiante per la riserva 🎉
Oggi abbiamo ricevuto una cospicua e apprezzatissima donazione anonima al progetto. Se anche voi volete aiutare questo piccolo vivaio collettivo a nascere, potete donare anche voi da qui! paypal.com/pools/c/9oPd2FIm3S
e poi chiedere qui il vostro regalo 😃 framaforms.org/mastobosco-un-v…
9oPd2FIm3S
www.paypal.comreshared this
rag. Gustavino Bevilacqua, Vespa cartolaia, Oblomov e Dario reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •Oggi al #GAS del Newroz di #Pisa come Lecciofanti abbiamo portato il banchetto di piante e semi benefit per il nostro nascituro vivaio collettivo ❤️
Tanto calore e sostegno che ci hanno permesso di arrivare a degli obiettivi minimi importanti, ma c'è ancora diversa strada da fare!
Domani io non ci sarò, ma i Lecciofanti saranno al Mercato Contadino di piazza Martiri (sempre a @pisa !) con tante piante per voi!
E se siete lontani potete sostenerci a questo link paypal.com/pools/c/9oPd2FIm3S
9oPd2FIm3S
www.paypal.comreshared this
Pisa e rag. Gustavino Bevilacqua reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •Lo scorso fine settimana, con le nostre due apparizioni su @pisa come Lecciofanti, siamo riusciti - vendendo piante - a racimolare un piccolo gruzzolo che ci avvicina molto ai nostri obiettivi per il Vivaio Collettivo! 💰 🌳
C'è ancora un po' di sforzo da fare, per cui vi chiediamo, a voi che magari siete lontani, di sostenerci con la raccolta #mastoBosco
paypal.com/pools/c/9oPd2FIm3S
ricordando che, compilando questo form, ci sono semi per voi! 🪴 📬
framaforms.org/mastobosco-un-v…
Grazie a tutti!
9oPd2FIm3S
www.paypal.comreshared this
Pisa, rag. Gustavino Bevilacqua, Oblomov, H9k, Matteo B., filobus e ORIENTAL ART SRL reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •Questa settimana son partiti i primi ordini per il vivaio collettivo, grazie ai vostri contributi! In qualche giorno chiuderemo la cisterna d'acqua e partiran anche gli ordini per la micro-irrigazione.
Aiutate il vivaio e le prossime piantumazioni di alberi a @pisa con la raccolta #mastoBosco!
paypal.com/pools/c/9oPd2FIm3S
ricordando che, compilando questo form, ci sono semi per voi! 🪴 📬
framaforms.org/mastobosco-un-v…
Grazie a tutti!
9oPd2FIm3S
www.paypal.comreshared this
Pisa, rag. Gustavino Bevilacqua e Oblomov reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •Pochi sostenitori della campagna #mastoBosco stanno chiedendo le loro buste di semi!
Ricordate che se sostenete il Vivaio Lecciofante, potete portarvi a casa un po' di semi! Risalite il thread per più informazioni. 🪴
Questa va in quel di Vercelli... fatemi sentire anche un po' di sud, mi raccomando!
reshared this
rag. Gustavino Bevilacqua, Dario, LaVi, Oblomov e Manuel 🦡🦡 ⚾ reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •Attenzione brava gente! 🌳📣
ULTIMA SETTIMANA per donare alla raccolta fondi #mastoBosco, che ci permetterà di metter in piedi un vivaio collettivo a @pisa e sostenere l'attività di #GuerrillaGardening e altre iniziative di rimboschimento!
paypal.com/pools/c/9oPd2FIm3S
Ricordate che se donate più del costo di un francobollo potrete ricevere a casa vostra dei semi per cimentarvi voi stessi nel piantare qualche albero! 🌱 Anche se avete solo un balcone!
framaforms.org/mastobosco-un-v…
Aiutateci a rinverdire!
MastoBosco! Un piccolo vivaio per Pisa.
www.paypal.comreshared this
Pisa, rag. Gustavino Bevilacqua, Oblomov e Gilberto Ficara reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •Buongiorno brava gente!
La raccolta fondi #mastoBosco, per la realizzazione di un vivaio collettivo per il rimboschimento a @pisa è terminata! Questa parte di #fediverso ha raccolto 140€ lordi, che insieme ai mercati di piante in città e le donazioni in persona ci ha fatto quasi raggiungere l'obiettivo e questa settimana sarà attiva la prima linea di irrigazione! 🌳
Pisa reshared this.
Gabriele Primavera
in reply to Gabriele Primavera • • •I nostri infiniti ringraziamenti vanno a:
- Francesco Apruzzese
- Simone Scamuzzi
- Ivan Ruggiero
- Linda Sartini
- Luca Alunni
e tutti gli anonimi donatori che hanno partecipato.
A breve ricevete testimonianza dei primi frutti della raccolta e mercoledì partiranno gli ultimi semi!
Un albero alla volta, ricostruiremo l'abbondanza! 🌳💪
Gabriele Primavera
in reply to Gabriele Primavera • • •Payez Gabriele Primavera avec PayPal.Me
PayPal.MeLinda Sartini reshared this.
🌚 I4Z 🌝
in reply to Gabriele Primavera • • •bellissima iniziativa, si può partecipare quando verranno piantati per dare una mano?
Grazie!
Girato l'iniziativa a tutta la rubrica
Gabriele Primavera
in reply to 🌚 I4Z 🌝 • • •