Partage via


Tutoriel : Utiliser C# pour faire correspondre les données à des modèles

Ce tutoriel vous explique comment utiliser la correspondance de modèle pour inspecter les données en C#. Vous écrivez de petites quantités de code, puis vous compilez et exécutez ce code. Ce didacticiel contient une série de leçons qui explorent différents types de modèles pris en charge par C#. Ces leçons vous enseignent les principes fondamentaux de la langue C#.

Dans ce tutoriel, vous allez :

  • Lancez un espace de code GitHub avec un environnement de développement C#.
  • Testez les données pour les valeurs discrètes.
  • Comparer les données d’énumération avec la valeur.
  • Créez des correspondances exhaustives à l’aide d’expressions switch .
  • Mettre en correspondance les types à l’aide de modèles de type.

Prerequisites

Vous devez disposer de l’un des éléments suivants :

Mettre en correspondance une valeur

Les didacticiels précédents ont montré les types intégrés et ceux que vous définissez sous forme de tuples ou d'enregistrements. Vous pouvez vérifier les instances de ces types par rapport à un modèle. Si une instance correspond à un modèle détermine les actions effectuées par votre programme. Dans les exemples ci-dessous, vous voyez ? après les noms de type. Ce symbole permet à la valeur de ce type d’être null (par exemple, bool? peut être true, falseou null). Pour plus d'informations, consultez types de valeur nullables. Commençons à explorer la façon dont vous pouvez utiliser des modèles.

Ouvrez une fenêtre de navigateur sur gitHub codespaces. Créez un nouvel espace de code à partir du modèle .NET. Si vous avez terminé d’autres didacticiels de cette série, vous pouvez ouvrir cet espace de code.

  1. Lorsque votre espace de code se charge, créez un fichier dans le dossier didacticiels nommé patterns.cs.

  2. Ouvrez votre nouveau fichier.

  3. Tous les exemples de ce didacticiel utilisent une entrée de texte qui représente une série de transactions bancaires sous forme d’entrée de valeurs séparées par des virgules (CSV). Dans chacun des échantillons, vous pouvez faire correspondre l’enregistrement à un modèle à l’aide d’une expression is ou switch. Ce premier exemple fractionne chaque ligne en utilisant le caractère , et compare le premier champ de chaîne à la valeur « DEPOSIT » ou « WITHDRAWAL » à l'aide d'une expression is. Lorsqu’il correspond, le montant de la transaction est ajouté ou déduit du solde du compte actuel. Pour le voir fonctionner, ajoutez le code suivant à patterns.cs :

    string bankRecords = """
        DEPOSIT,   10000, Initial balance
        DEPOSIT,     500, regular deposit
        WITHDRAWAL, 1000, rent
        DEPOSIT,    2000, freelance payment
        WITHDRAWAL,  300, groceries
        DEPOSIT,     700, gift from friend
        WITHDRAWAL,  150, utility bill
        DEPOSIT,    1200, tax refund
        WITHDRAWAL,  500, car maintenance
        DEPOSIT,     400, cashback reward
        WITHDRAWAL,  250, dining out
        DEPOSIT,    3000, bonus payment
        WITHDRAWAL,  800, loan repayment
        DEPOSIT,     600, stock dividends
        WITHDRAWAL,  100, subscription fee
        DEPOSIT,    1500, side hustle income
        WITHDRAWAL,  200, fuel expenses
        DEPOSIT,     900, refund from store
        WITHDRAWAL,  350, shopping
        DEPOSIT,    2500, project milestone payment
        WITHDRAWAL,  400, entertainment
        """;
    
    double currentBalance = 0.0;
    var reader = new StringReader(bankRecords);
    
    string? line;
    while ((line = reader.ReadLine()) is not null)
    {
        if (string.IsNullOrWhiteSpace(line)) continue;
        // Split the line based on comma delimiter and trim each part
        string[] parts = line.Split(',');
    
        string? transactionType = parts[0]?.Trim();
        if (double.TryParse(parts[1].Trim(), out double amount))
        {
            // Update the balance based on transaction type
            if (transactionType?.ToUpper() is "DEPOSIT")
                currentBalance += amount;
            else if (transactionType?.ToUpper() is "WITHDRAWAL")
                currentBalance -= amount;
    
            Console.WriteLine($"{line.Trim()} => Parsed Amount: {amount}, New Balance: {currentBalance}");
        }
    }
    
  4. Tapez ensuite le texte suivant dans la fenêtre de terminal :

    cd tutorials
    dotnet patterns.cs
    
  5. Examinez le résultat. Vous pouvez voir que chaque ligne est traitée en comparant la valeur du texte dans le premier champ.

Vous pouvez également construire l’exemple précédent à l’aide de l’opérateur == pour tester que deux string valeurs sont égales. La comparaison d’une variable à une constante est un bloc de construction de base pour la mise en correspondance des modèles. Examinons davantage les blocs de construction qui font partie de la mise en correspondance des modèles.

Correspondances d’énumération

Une autre utilisation courante de la correspondance des modèles est la correspondance basée sur les valeurs du type enum. L’exemple suivant traite les enregistrements d’entrée pour créer un tuple où la première valeur est une enum valeur qui note un dépôt ou un retrait. La deuxième valeur est la valeur de la transaction.

  1. Ajoutez le code suivant à la fin de votre fichier source. Il définit l’énumération TransactionType :

    public enum TransactionType
    {
        Deposit,
        Withdrawal,
        Invalid
    }
    
  2. Ajoutez une fonction pour analyser une transaction bancaire dans un tuple qui contient le type de transaction et la valeur de la transaction. Ajoutez le code suivant avant votre déclaration de l’énumération TransactionType :

    static IEnumerable<(TransactionType type, double amount)> TransactionRecords(string inputText)
    {
        var reader = new StringReader(inputText);
        string? line;
        while ((line = reader.ReadLine()) is not null)
        {
            string[] parts = line.Split(',');
    
            string? transactionType = parts[0]?.Trim();
            if (double.TryParse(parts[1].Trim(), out double amount))
            {
                // Update the balance based on transaction type
                if (transactionType?.ToUpper() is "DEPOSIT")
                    yield return (TransactionType.Deposit, amount);
                else if (transactionType?.ToUpper() is "WITHDRAWAL")
                    yield return (TransactionType.Withdrawal, amount);
            }
            else {
            yield return (TransactionType.Invalid, 0.0);
            }
        }
    }
    
  3. Ajoutez une nouvelle boucle pour traiter les données de transaction à l’aide de l’énumération TransactionType que vous avez déclarée :

    currentBalance = 0.0;
    
    foreach (var transaction in TransactionRecords(bankRecords))
    {
        if (transaction.type == TransactionType.Deposit)
            currentBalance += transaction.amount;
        else if (transaction.type == TransactionType.Withdrawal)
            currentBalance -= transaction.amount;
        Console.WriteLine($"{transaction.type} => Parsed Amount: {transaction.amount}, New Balance: {currentBalance}");
    }
    

L’exemple précédent utilise également une if instruction pour vérifier la valeur d’une enum expression. Une autre forme de correspondance de modèle utilise une switch expression. Examinons cette syntaxe et la façon dont vous pouvez l’utiliser.

Correspondances exhaustives avec switch

Une série d’instructions if peut tester une série de conditions. Toutefois, le compilateur ne peut pas savoir si une série d’instructions if est exhaustive ou si des conditions if sont subordonnées par des conditions antérieures. Exhaustive signifie que l’une if des ou else clauses de la série de tests gère toutes les entrées possibles. Si une série d'instructions if est exhaustive, chaque entrée possible satisfait au moins une clause if ou else. La subsomption signifie qu'une clause if ou else ultérieure ne peut pas être atteinte, car les clauses antérieures if ou else correspondent à toutes les entrées possibles. Par exemple, dans l’exemple de code suivant, une clause ne correspond jamais :

int n = GetNumber();

if (n < 20)
    Console.WriteLine("n is less than 20");
else if (n < 10)
    Console.WriteLine("n is less than 10"); // unreachable
else
    Console.WriteLine("n is greater than 20");

La else if clause ne correspond jamais, car chaque nombre inférieur à 10 est également inférieur à 20. L’expression switch garantit que ces deux caractéristiques sont remplies, ce qui entraîne moins de bogues dans vos applications. Essayons-le et expérimentons.

  1. Copiez le code suivant. Remplacez les deux if instructions de votre foreach boucle par l’expression switch que vous avez copiée.

    currentBalance += transaction switch
    {
        (TransactionType.Deposit, var amount) => amount,
        (TransactionType.Withdrawal, var amount) => -amount,
        _ => 0.0,
    };
    
  2. Tapez dotnet patterns.cs dans la fenêtre de terminal pour exécuter le nouvel exemple.

    Lorsque vous exécutez le code, vous voyez qu’il fonctionne de la même façon.

  3. Pour illustrer la sous-énumération, réorganisez les bras de commutateur comme indiqué dans l’extrait de code suivant :

    currentBalance += transaction switch
    {
        (TransactionType.Deposit, var amount) => amount,
        _ => 0.0,
        (TransactionType.Withdrawal, var amount) => -amount,
    };
    

    Après avoir réorganisé les bras de commutateur, tapez dotnet patterns.cs dans la fenêtre de terminal. Le compilateur émet une erreur, car le bras avec _ correspond à chaque valeur. Par conséquent, ce bras final avec TransactionType.Withdrawal ne s’exécute jamais. Le compilateur vous indique que quelque chose ne va pas dans votre code.

    Le compilateur émet un avertissement si l’expression testée dans une switch expression peut contenir des valeurs qui ne correspondent à aucun bras de commutateur. Si certaines valeurs peuvent ne pas correspondre à une condition, l’expression switch n’est pas exhaustive. Le compilateur émet également un avertissement si certaines valeurs de l’entrée ne correspondent pas aux bras de commutateur.

  4. Supprimez la ligne avec _ => 0.0,, afin que les valeurs non valides ne correspondent pas.

  5. Tapez dotnet patterns.cs pour afficher les résultats.

    Le compilateur émet un avertissement. Les données de test sont valides. Le programme fonctionne donc. Toutefois, toutes les données non valides provoquent un échec lors de l’exécution.

Modèles de type

Pour terminer ce tutoriel, explorez un bloc de construction supplémentaire pour la mise en correspondance des modèles : le modèle de type. Un modèle de type teste une expression au moment de l’exécution pour voir s’il s’agit du type spécifié. Vous pouvez utiliser un test de type avec une is expression ou une switch expression. Modifiez l’exemple actuel de deux façons. Tout d'abord, au lieu d'un tuple, créez des types d'enregistrement Deposit et Withdrawal qui représentent les transactions.

  1. Ajoutez les déclarations suivantes à la fin de votre fichier de code :

    public record Deposit(double Amount, string description);
    public record Withdrawal(double Amount, string description);
    
  2. Ajoutez cette méthode juste avant la déclaration de l’énumération TransactionType . Il analyse le texte et retourne une série d’enregistrements :

    static IEnumerable<object?> TransactionRecordType(string inputText)
    {
        var reader = new StringReader(inputText);
        string? line;
        while ((line = reader.ReadLine()) is not null)
        {
            string[] parts = line.Split(',');
    
            string? transactionType = parts[0]?.Trim();
            if (double.TryParse(parts[1].Trim(), out double amount))
            {
                // Update the balance based on transaction type
                if (transactionType?.ToUpper() is "DEPOSIT")
                    yield return new Deposit(amount, parts[2]);
                else if (transactionType?.ToUpper() is "WITHDRAWAL")
                    yield return new Withdrawal(amount, parts[2]);
            }
            yield return default;
        }
    }
    
  3. Ajoutez le code suivant après la dernière foreach boucle :

    currentBalance = 0.0;
    
    foreach (var transaction in TransactionRecordType(bankRecords))
    {
        currentBalance += transaction switch
        {
            Deposit d => d.Amount,
            Withdrawal w => -w.Amount,
            _ => 0.0,
        };
        Console.WriteLine($" {transaction} => New Balance: {currentBalance}");
    }
    
  4. Tapez dotnet patterns.cs dans la fenêtre de terminal pour afficher les résultats. Cette version finale teste l’entrée par rapport à un type.

La mise en correspondance des modèles fournit un vocabulaire pour comparer une expression par rapport aux caractéristiques. Les modèles peuvent inclure le type, les valeurs des types, les valeurs des propriétés et les combinaisons d’expressions. La comparaison d’expressions par rapport à un modèle peut être plus claire que plusieurs if comparaisons. Vous avez exploré certains des modèles que vous pouvez utiliser pour faire correspondre des expressions. Il existe de nombreuses façons d’utiliser la correspondance de modèles dans vos applications. À mesure que vous explorez, vous pouvez en savoir plus sur la correspondance des modèles en C# dans les articles suivants :

Nettoyer les ressources

GitHub supprime automatiquement votre Espace de code après 30 jours d’inactivité. Vous avez terminé tous les tutoriels de cette série. Pour supprimer votre espace de code maintenant, ouvrez une fenêtre de navigateur et accédez à vos espaces de code. Vous devez voir une liste de vos espaces de code dans la fenêtre. Sélectionnez les trois points (...) dans l’entrée de l’espace de code du didacticiel Learn, puis sélectionnez Supprimer.