Aller au contenu

Pattern matching

Introduction

Apparu avec la version 7 du langage C#, le Pattern Matching est une fonctionnalité très utilisée, pour écrire du code à la fois concis et compréhensif, facilitant l'évolutivité et la maintenabilité du code.

Cette version proposait trois formes de Pattern Matching : le Declaration Pattern, le Constant Pattern et le Type Pattern dans l'instruction switch.

La version 8 du langage C# a étendu le Pattern Matching en introduisant le Property Patterns, Positional Patterns et les Switch Expressions.

La version 9 a proposé le nouveaux Pattern Matching : les Relational Patterns (<, >, <=, >=), les Logical Patterns (and, or, not) et les Parenthesized Patterns

La version 11 a étendu ce concept aux listes avec les List Patterns.

Le Declaration Pattern

Le Declaration Pattern permet de vérifier le type d'un objet, tout en déclarant une variable fortement typée utilisable immédiatement dans le bloc de code courant :

if (shape is Circle circle)
    Console.WriteLine(circle.Radius);

qui est une simplification de ce bloc de code :

var circle = shape as Circle;
if (circle != null)
    Console.WriteLine(circle.Radius);

Le Constant Pattern

Le Constant Pattern permet de comparer directement une valeur à une constante, dans une expression is ou un switch :

if (value is 79)
{
    ...
}

if (content is null)
{
    ...
}

Concernant la vérification de la nullité d'un objet, cette syntaxe est devenue la manière recommandée de l'implémenter, car elle n'utilise pas un éventuel opérateur == surchargé.

Le switch avec Pattern Matching

Le Pattern Matching permet d'utiliser des patterns directement dans les clauses case de l'instruction switch. Il devient possible de tester le type d'un objet, de comparer des valeurs ou de déclarer une variable typée, rendant les instructions switch plus expressives :

switch (shape)
{
    case Circle circle:
        Console.WriteLine(circle.Radius);
        break;

    case Rectangle rectangle:
        Console.WriteLine(rectangle.Width);
        break;
}

Le Property Pattern

Le Property Pattern permet de vérifier la valeur d'une ou plusieurs propriétés d'un objet, directement dans une expression is ou un switch. Il propose une syntaxe plus concise, plus lisible que l'enchaînement de plusieurs conditions avec l'opérateur logique && :

if (customer is { Country: "France", 
                  IsPremium: true, 
                  TotalOrders: > 1000 })
{
    ...
}

Le Positional Pattern

Le Positional Pattern permet de comparer les valeurs d'un objet en fonction de sa décomposition positionnelle (l'objet est vu comme une suite ordonnée de valeurs). Ce pattern est particulièrement adapté aux record et aux types qui implémentent une méthode Deconstruct. Voici un exemple :

public record Point(int X, int Y);

if (point is (0, 0))
    Console.WriteLine("Le point est à l'origine.");

Le Switch Expression

Le Switch Expression permet d'obtenir une valeur en fonction de différents cas, avec une syntaxe plus concise et plus expressive que l'instruction switch classique. Il s'utilise avec d'autres types de patterns :

var category = customer switch { 
    { IsPremium: true, TotalOrders: > 1000 } => "Client stratégique",
    { IsPremium: true } => "Client premium", _ => "Client standard" 
};

Le Relational Pattern

Le Relational Pattern permet de comparer une valeur à l'aide des opérateurs relationnels (<, <=, >, >=) directement dans une expression de pattern. Il propose une lecture plus simple et s'intègre naturellement aux expressions is et switch :

if (age is >= 18) 
{
    ...
}

Le Logical Pattern

Le Logical Pattern permet de combiner plusieurs patterns avec les opérateurs logiques and, or et not. Il rend les expressions booléennes plus expressives, notamment lorsqu'une valeur doit respecter plusieurs critères :

if (age is >= 18 and < 30)
{
    ...
}

if (status is not Statuses.Cancelled)
{
    ...
}

Le Parenthesized Pattern

Le Parenthesized Pattern permet d'ajouter des parenthèses autour d'un pattern afin de clarifier l'ordre d'évaluation, notamment lorsqu'on combine plusieurs conditions avec les opérateurs and et or.

if (age is >= 18 and (< 25 or > 35))
{
    ...
}

Le List Pattern

Le List Pattern permet de comparer directement le contenu et la structure d'une collection ou d'un tableau. Il facilite la vérification du nombre d'éléments, de leur ordre et de leurs valeurs à l'aide d'une syntaxe concise.

if (numbers is [2, 4, .., 20])
    Console.WriteLine("La collection commence par 2, 4 et se termine par 20");