Krijg meer gedaan met C# pattern matching

Contenttype
Blog

Deze blog biedt een praktisch overzicht van C# pattern matching en laat zien hoe moderne patterns bijdragen aan compactere, beter leesbare en onderhoudbare code.

Krijg Meer Gedaan Met C# Pattern Matching
Auteur
Christian Peeters

C# bestaat inmiddels ruim vijfentwintig jaar en is in die tijd flink doorontwikkeld. De taal heeft er veel features bij gekregen, zoals generics, async en await, LINQ, auto-properties, records, top-level statements en global usings.

Code uit de begintijd werkt nog steeds prima, maar dat betekent niet dat de taal heeft stilgestaan. Integendeel. Er zijn de afgelopen jaren veel mogelijkheden toegevoegd die je helpen om korter, duidelijker en productiever te werken.

Als je al langer met C# werkt, is de kans groot dat je vooral vertrouwt op syntax die je gewend bent. Daardoor mis je soms verbeteringen die je code juist eenvoudiger maken.

Pattern matching is daar een goed voorbeeld van. Zeker in combinatie met switch-expressies levert het vaak direct winst op in leesbaarheid en onderhoudbaarheid.

Switch syntax

Laten we beginnen met de bekende switch. Net als bij methodes kun je in C# veel boilerplate weglaten door gebruik te maken van de arrow syntax, oftewel switch expressions. Deze zijn geïntroduceerd in C# 8.

Hieronder zie je twee keer dezelfde implementatie. De switch expression is een stuk compacter en maakt de intentie direct duidelijk.

De code spreekt grotendeels voor zich, maar één detail is goed om uit te lichten: de underscore “_” in de onderste switch.

In C# is _ een discard. Dit is een opzettelijk ongebruikte variabele. Je gebruikt die bijvoorbeeld wanneer je een methode aanroept, maar niet geïnteresseerd bent in de return value.

Binnen een switch statement betekent een discard dat alles gematcht wordt, inclusief null. Als number dus niet gelijk is aan 1 of 2, matcht deze met de discard en wordt "unknown" geretourneerd. Dit is vergelijkbaar met de default in het bovenste voorbeeld.

Discards komen we later nog op een andere manier tegen bij list pattern matching.

Type pattern matching

Wat is pattern matching? In de basis controleer je of een expressie, bijvoorbeeld een variabele, voldoet aan bepaalde kenmerken. Dat kan een concrete waarde zijn, maar ook een eigenschap zoals het type.

In het eerdere voorbeeld vergelijken we een variabele met één specifieke waarde. Maar je kunt ook matchen op andere kenmerken, zoals het type van een object.

Afhankelijk van het type van item wordt een andere methode aangeroepen. Door achter het type direct een naam te zetten, ontstaat automatisch een variabele van dat type.

De variabele someType verwijst naar hetzelfde object als item, maar dan al gecast naar SomeType. Een expliciete cast is dus niet meer nodig.

Relational en Logical pattern matching

Soms wil je niet op één specifieke waarde controleren, maar bijvoorbeeld of een waarde binnen een bepaalde range valt. Daarvoor gebruik je relational pattern matching.

In het onderstaande voorbeeld vergelijken we de expressie result met behulp van operators zoals <, >, <= en >=.

Dit kun je combineren met logical pattern matching. Met and en or stel je eenvoudig combinaties samen, zodat je bijvoorbeeld kunt controleren of een waarde binnen een bepaalde range ligt.

Property pattern matching

Tot nu toe hebben we gekeken naar eenvoudige waardes. Met property pattern matching kun je ook eigenschappen van objecten gebruiken in je match.

In het eerste voorbeeld kijken we naar de Length van de string name.

We kunnen dit een stap verder brengen door een complexer type te bekijken. In het volgende voorbeeld gebruiken we een Order object met de properties Cost en Items. Items is een array van het Type OrderDetails, dat op zijn beurt ook weer twee properties bevat.

Met pattern matching kun je deze eigenschappen direct gebruiken om business rules toe te passen. In het onderstaande voorbeeld wordt bijvoorbeeld de korting bepaald op basis van het aantal orderregels en de waarde van Cost.

Positional pattern matching

In de vorige voorbeelden gingen we steeds uit van één expressie waarop we een patroon toepassen. Met positional pattern matching kun je meerdere inputs combineren.

Deze inputs vormen samen een tuple, waarop je per positie een patroon kunt definiëren.

In het onderstaande voorbeeld gebruiken we twee variabelen: groupSize en visitDate. De eerste input voor de switch is groupSize. Van visitDate gebruiken we de DayOfWeek als tweede input.

In de patterns wordt dus op twee posities gematcht:

  • Groepen kleiner of gelijk aan 0 geven een foutmelding, ongeacht de dag
  • In het weekend is er geen korting, ongeacht de groepsgrootte
  • Groepen van 5 tot en met 9 personen krijgen op maandag 20 procent korting, grotere groepen 30 procent
  • Op de overige dagen is dat respectievelijk 12 en 15 procent
  • In alle andere gevallen is er geen korting

Omdat er maar één puntkomma (;) staat, zit deze volledige logica in één expressie. Daarmee is in één regel een vrij uitgebreid stuk businesslogica vastgelegd.

Var pattern matching

We kunnen positional pattern matching combineren met var pattern matching. Met het keyword var maak je binnen een pattern direct een nieuwe variabele aan die je verderop kunt gebruiken.

Dat is bijvoorbeeld handig voor tussentijdse berekeningen. In het voorbeeld gebruiken we een Order met twee properties. De eerste slaan we op in de variabele items en de tweede in cost. Vervolgens gebruiken we de Amount van de items om een aggregatie te doen en deze te vergelijken met cost.

Voor de volledigheid nog een korte toelichting op het statement achter de => arrow.

Order is hier gedefinieerd als record. Met het “with” keyword maak je een kopie van order, waarbij je één property aanpast. In dit geval wordt de Cost vervangen door een nieuwe waarde: in het ene geval de som van de bedragen en in het andere geval 0.

Op deze manier voer je eenvoudig een transformatie uit op het Order object, zonder het originele object aan te passen.

List pattern matching

Naast waardes en objecten kun je ook collecties matchen op patronen. Dit noemen we list pattern matching. Deze mogelijkheid is toegevoegd in C# 11.

In het onderstaande voorbeeld zie je hoe een array numbers wordt gematcht tegen verschillende patronen. Dit is goed te combineren met relational- en logical pattern matching, waardoor je vrij complexe patronen kunt definiëren.

Dit werkt uiteraard niet alleen met getallen, maar ook met andere types. In het volgende voorbeeld gebruiken we strings.

In het tweede patroon wordt de discard “_” gebruikt om precies één element te matchen. De twee puntjes “..” vormen de range operator en staan voor nul of meer elementen.

In het derde patroon wordt de reeks tussen het eerste en laatste element opgeslagen in de variabele tussenvoegsels, die we na de arrow weer kunnen gebruiken.

Hieronder zie je welke output hoort bij de verschillende aanroepen van de ProcessName methode.

Tot slot kijken we naar een praktisch voorbeeld: het parsen van een CSV (Comma Seperated Value).

De inputdata is niet netjes gestructureerd. Regels met “WITHDRAWAL” bevatten extra kolommen, terwijl regels met “Interest” en “FEE” juist minder kolommen hebben. Toch willen we deze data verwerken en een saldo berekenen.

In onderstaande methode worden de regels opgesplitst en gescheiden op komma. Door middel van list pattern matching wordt gecontroleerd welke bewerking het betreft en wordt de laatste waarde in de variabele amount opgeslagen. Deze wordt vervolgens geparst naar een decimaal en opgeteld bij de variabele balance.

In de onderstaande methode worden de regels opgesplitst op komma’s. Met list pattern matching bepalen we per regel welk type bewerking het is. De relevante waarde wordt opgeslagen in de variabele amount, geparsed naar een decimaal en verwerkt in de variabele balance.

Zonder complexe parsinglogica of geneste if-constructies.

Pattern matching blijkt hier niet alleen krachtig, maar ook goed leesbaar.

Hopelijk geeft dit overzicht een goed beeld van wat er mogelijk is. Pattern matching helpt om code compacter en onderhoudbaarder te maken. En omdat er bij vrijwel elke nieuwe versie van C# uitbreidingen bijkomen, blijft het een onderwerp waar je als ontwikkelaar voordeel uit kunt halen.

De voorbeelden in deze blog zijn ook terug te vinden op GitHub.

Meer informatie over Microsoft oplossingen, C# of .NET?

Neem dan gerust contact met ons op of bespreek jouw specifieke situatie.

Meer blogposts

  • JSON data opslaan in SQL databases

    Deze blog gaat over hoe JSON-data opgeslagen en verwerkt kan worden binnen SQL Server en Azure SQL Database, en hoe de ingebouwde JSON-functionaliteiten flexibel werken met schemaless data mogelijk maken zonder voortdurende wijzigingen aan het databaseschema.
    Contenttype
    Blog
    JSON Data Opslaan In SQL Databases
  • Regex in SQL Server 2025 & Azure SQL

    SQL Server 2025 introduceert native regex-ondersteuning, waarmee patroonherkenning, validatie en datatransformatie eenvoudiger, leesbaarder en beter onderhoudbaar worden dan met traditionele stringfuncties.
    Contenttype
    Blog
    Regex In SQL Server 2025 & Azure SQL Blog
  • Blind SQL injection: wat het is en hoe je het voorkomt

    Introductie tot SQL-injectie en Blind SQL-injectie: hoe aanvallers data uitlezen en manipuleren en hoe je dit voorkomt met veilige technieken zoals parameterized queries en inputvalidatie.
    Contenttype
    Blog
    Blind SQL Injection What It Is And How To Prevent It

Altijd op de hoogte met onze tech-updates!

Schrijf je in en ontvang om de week een update met de nieuwste kennis en ontwikkelingen.