Delen via


Gegevens vergelijken met patronen

In deze zelfstudie leert u hoe u patroonkoppeling gebruikt om gegevens in C# te inspecteren. U schrijft kleine hoeveelheden code, vervolgens compileert en voert u die code uit. De zelfstudie bevat een reeks lessen die verschillende soorten typen in C# verkennen. In deze lessen leert u de basisprincipes van de C#-taal.

Aanbeveling

Wanneer een codefragmentblok de knop Uitvoeren bevat, wordt het interactieve venster geopend of wordt de bestaande code in het interactieve venster vervangen. Wanneer het codefragment geen knop Uitvoeren bevat, kunt u de code kopiëren en toevoegen aan het huidige interactieve venster.

In de voorgaande zelfstudies zijn ingebouwde typen en typen gedemonstreerd die u definieert als tuples of records. Exemplaren van deze typen kunnen worden gecontroleerd op basis van een patroon. Of een exemplaar overeenkomt met een patroon bepaalt welke acties uw programma uitvoert. In de onderstaande voorbeelden ziet u ? na typenamen. Met dit symbool kan de waarde van dit type nul zijn (bijvoorbeeld bool? kan true, false of null). Zie Nullable-waardetypen voor meer informatie. Laten we eens kijken hoe u patronen kunt gebruiken.

Een waarde vergelijken

Alle voorbeelden in deze zelfstudie gebruiken tekstinvoer die een reeks banktransacties vertegenwoordigt als csv-invoer (door komma's gescheiden waarden). In elk van de voorbeelden kunt u de record vergelijken met een patroon met behulp van een is of switch expressie. In dit eerste voorbeeld wordt elke regel op het , teken gesplitst en vervolgens wordt het eerste tekenreeksveld vergeleken met de waarde "DEPOSIT" of "WITHDRAWAL" met behulp van een is expressie. Wanneer het overeenkomt, wordt het transactiebedrag opgeteld of afgetrokken van het huidige rekeningsaldo. Druk op de knop "Uitvoeren" om te zien hoe het werkt.

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}");
    }
}

Bekijk de uitvoer. U kunt zien dat elke regel wordt verwerkt door de waarde van de tekst in het eerste veld te vergelijken. Het voorgaande voorbeeld kan op dezelfde manier worden samengesteld met behulp van de == operator om te testen of twee string waarden gelijk zijn. Het vergelijken van een variabele met een constante is een basisbouwsteen voor patroonkoppeling. Laten we eens kijken naar meer bouwstenen die deel uitmaken van patroonkoppeling.

Enum-overeenkomsten

Een ander veelvoorkomend gebruik voor patroonkoppeling is om overeen te komen met de waarden van een enum type. In dit volgende voorbeeld worden de invoerrecords verwerkt om een tuple te maken waarbij de eerste waarde een enum waarde is die een storting of een intrekking noteert. De tweede waarde is de waarde van de transactie. Druk op de knop "Uitvoeren" om te zien hoe het werkt.

Waarschuwing

Kopieer en plak niet. Het interactieve venster moet opnieuw worden ingesteld om de volgende voorbeelden uit te voeren. Als u een fout maakt, loopt het venster vast en moet u de pagina vernieuwen om door te gaan.

public static class ExampleProgram
{
    const 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
    """;

    public static void Main()
    {
        double 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}");
        }
    }

    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);
            }
        }
    }
}

public enum TransactionType
{
    Deposit,
    Withdrawal,
    Invalid
}

In het voorgaande voorbeeld wordt ook een if instructie gebruikt om de waarde van een enum expressie te controleren. Een andere vorm van patroonkoppeling maakt gebruik van een switch expressie. Laten we die syntaxis verkennen en hoe u deze kunt gebruiken.

Volledige overeenkomsten met switch

Een reeks if instructies kan een reeks voorwaarden testen. Maar de compiler kan niet zien of een reeks if instructies volledig is of als latere if voorwaarden worden aangevuld met eerdere voorwaarden. De switch expressie zorgt ervoor dat aan beide kenmerken wordt voldaan, wat resulteert in minder fouten in uw apps. Laten we het proberen en experimenteren. Kopieer de volgende code. Vervang de twee if instructies in het interactieve venster door de switch expressie die u hebt gekopieerd. Nadat u de code hebt gewijzigd, drukt u boven aan het interactieve venster op de knop Uitvoeren om het nieuwe voorbeeld uit te voeren.

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

Wanneer u de code uitvoert, ziet u dat deze hetzelfde werkt. Als u de subsumptie wilt demonstreren, rangschikt u de schakelarmen zoals weergegeven in het volgende fragment.

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

Nadat u de schakelarmen opnieuw hebt gerangschikt, drukt u op de knop Uitvoeren. De compiler geeft een fout op omdat de arm met _ overeenkomt met elke waarde. Als gevolg hiervan wordt die laatste arm met TransactionType.Withdrawal nooit uitgevoerd. De compiler vertelt u dat er iets mis is in uw code.

De compiler geeft een waarschuwing uit als de expressie die is getest in een switch expressie waarden kan bevatten die niet overeenkomen met een schakelarm. Als sommige waarden niet overeenkomen met een voorwaarde, is de switch expressie niet volledig. De compiler geeft ook een waarschuwing als sommige waarden van de invoer niet overeenkomen met een van de schakelarmen. Als u bijvoorbeeld de regel met _ => 0.0,verwijdert, komen ongeldige waarden niet overeen. Tijdens runtime zou dat mislukken. Zodra u de .NET SDK hebt geïnstalleerd en programma's in uw omgeving hebt gebouwd, kunt u dit gedrag testen. In de onlineervaring worden geen waarschuwingen weergegeven in het uitvoervenster.

Typepatronen

Als u deze zelfstudie wilt voltooien, gaan we nog een bouwsteen voor patroonkoppelingen verkennen: het typepatroon. Een typepatroon test een expressie tijdens runtime om te zien of dit het opgegeven type is. U kunt een typetest gebruiken met een is expressie of een switch expressie. Laten we het huidige voorbeeld op twee manieren wijzigen. Eerst gaan we in plaats van een tuple typen bouwen Deposit en Withdrawal opnemen die de transacties vertegenwoordigen. Voeg de volgende declaraties onder aan het interactieve venster toe:

public record Deposit(double Amount, string description);
public record Withdrawal(double Amount, string description);

Voeg vervolgens deze methode toe na de Main methode om de tekst te parseren en een reeks records te retourneren:

public 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;
    }
}

Vervang ten slotte de foreach lus in de Main methode door de volgende code:

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}");
}

Druk vervolgens op de knop Uitvoeren om de resultaten te bekijken. Met deze definitieve versie wordt de invoer getest op een type.

Patroonkoppeling biedt een woordenlijst om een expressie te vergelijken met kenmerken. Patronen kunnen het type, de waarden van typen, eigenschapswaarden en combinaties van deze expressies bevatten. Het vergelijken van expressies met een patroon kan duidelijker zijn dan meerdere if vergelijkingen. U hebt enkele van de patronen verkend die u kunt gebruiken om expressies te vergelijken. Er zijn nog veel meer manieren om patroonkoppeling in uw toepassingen te gebruiken. Ga eerst naar de .NET-site om de .NET SDK te downloaden, een project op uw computer te maken en codering te behouden. Tijdens het verkennen vindt u meer informatie over patroonkoppeling in C# in de volgende artikelen: