Sdílet prostřednictvím


Porovnávání dat se vzory

V tomto kurzu se naučíte používat porovnávání vzorů ke kontrole dat v jazyce C#. Napíšete malé množství kódu, pak tento kód zkompilujete a spustíte. Tento kurz obsahuje řadu lekcí, které prozkoumávají různé typy typů v jazyce C#. Tyto lekce vás naučí základy jazyka C#.

Návod

Když blok fragmentu kódu obsahuje tlačítko Spustit, otevře se interaktivní okno nebo nahradí stávající kód v interaktivním okně. Pokud fragment kódu neobsahuje tlačítko Spustit, můžete kód zkopírovat a přidat ho do aktuálního interaktivního okna.

Předchozí kurzy demonstrovaly předdefinované typy a typy, které definujete jako řazené kolekce členů nebo záznamy. Instanci těchto typů lze zkontrolovat proti vzoru. Jestli instance odpovídá vzoru, určuje akce, které váš program provede. V následujících příkladech si všimnete ? po názvech typů. Tento symbol umožňuje, aby hodnota tohoto typu byla null (například bool? může být true, false nebo null). Další informace naleznete v tématu nulovatelné typy hodnot. Pojďme se podívat, jak můžete používat vzory.

Přiřadit hodnotu

Všechny příklady v tomto kurzu používají textový vstup, který představuje řadu bankovních transakcí jako vstup hodnot oddělených čárkami (CSV). V každé ukázce můžete záznam spárovat se vzorem pomocí buď is výrazu, nebo switch výrazu. Tento první příklad rozdělí každý řádek na znak , a pak porovná první řetězcové pole proti hodnotě "DEPOSIT" nebo "WITHDRAWAL" pomocí výrazu . Když se shoduje, částka transakce se přidá nebo odečte od aktuálního zůstatku účtu. Pokud chcete vidět, jak funguje, stiskněte tlačítko Spustit:

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

Prozkoumejte výstup. Můžete vidět, že každý řádek je zpracován porovnáním hodnoty textu v prvním poli. Předchozí vzorek by mohl být podobně vytvořen pomocí operátoru == k otestování, že jsou dvě string hodnoty stejné. Porovnání proměnné s konstantou je základním stavebním blokem pro porovnávání vzorů. Pojďme se podívat na další stavební bloky, které jsou součástí porovnávání vzorů.

Shody výčtového typu

Dalším běžným použitím vyhledávání podle vzoru je porovnávání hodnot typu enum. Tato další ukázka zpracuje vstupní záznamy a vytvoří n-tici, kde první hodnota je enum hodnota, která zaznamenává vklad nebo výběr. Druhá hodnota je hodnota transakce. Pokud chcete vidět, jak funguje, stiskněte tlačítko Spustit:

Výstraha

Nekopírujte a nevkládejte. Aby bylo možné spustit následující ukázky, je nutné obnovit interaktivní okno. Pokud uděláte chybu, okno přestane reagovat a budete muset stránku aktualizovat, abyste mohli pokračovat.

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
}

Předchozí příklad také používá příkaz if ke kontrole hodnoty výrazu enum . Jiná forma porovnávání vzorů používá výraz switch. Pojďme se na tuto syntaxi podívat a jak ji můžete použít.

Vyčerpávající shody s switch

if Řada příkazů může testovat řadu podmínek. Kompilátor ale nemůže zjistit, jestli je řada if příkazů úplná nebo jestli jsou pozdější if podmínky přehlíženy dřívějšími podmínkami. Výraz switch zajistí splnění obou těchto vlastností, což vede k menšímu počtu chyb ve vašich aplikacích. Pojďme to vyzkoušet a experimentovat. Zkopírujte následující kód. Nahraďte dva if příkazy v interaktivním okně výrazem switch , který jste zkopírovali. Po úpravě kódu spusťte novou ukázku stisknutím tlačítka Spustit v horní části interaktivního okna.

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

Když kód spustíte, uvidíte, že funguje stejně. Pokud chcete předvést subsumption, změňte pořadí ramen přepínače, jak je znázorněno v následujícím fragmentu kódu:

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

Po změně pořadí přeuspořádejte ramena přepínače stisknutím tlačítka Spustit. Kompilátor vydá chybu, protože příkaz _ odpovídá každé hodnotě. Výsledkem je, že konečná větev s TransactionType.Withdrawal nikdy neprobíhá. Kompilátor vám řekne, že v kódu něco není v pořádku.

Kompilátor vydá upozornění, pokud výraz testovaný ve výrazu switch může obsahovat hodnoty, které neodpovídají žádné větvi přepínače. Pokud by některé hodnoty nemohly odpovídat žádné podmínce, switch výraz není vyčerpávající. Kompilátor také vydá upozornění, pokud některé hodnoty vstupu neodpovídají žádné z přepínacích ramen. Pokud například odeberete řádek s _ => 0.0,, všechny neplatné hodnoty se neshodují. Při běhu programu to selže. Po instalaci sady .NET SDK a sestavení programů ve vašem prostředí můžete toto chování otestovat. Online prostředí nezobrazuje upozornění v okně výstupu.

Vzory typů

Abychom dokončili tento tutoriál, prozkoumejme ještě jeden stavební blok pro porovnávání vzorů: typový vzor. Vzor typu testuje výraz za běhu, aby zjistil, jestli se jedná o zadaný typ. Test typu můžete použít buď s výrazem is , nebo výrazem switch . Pojďme aktuální ukázku upravit dvěma způsoby. Nejprve místo n-tice navrhněme Deposit a Withdrawal typy záznamů, které představují transakce. Do dolní části interaktivního okna přidejte následující deklarace:

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

Dále přidejte tuto metodu za metodu Main pro parsování textu a vrácení řady záznamů:

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

Nakonec nahraďte smyčku foreach v metodě Main následujícím kódem.

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

Pak výsledky zobrazíte stisknutím tlačítka Spustit. Tato konečná verze testuje vstup proti typu.

Porovnávání vzorů poskytuje slovní zásobu pro porovnání výrazu s charakteristikami. Vzory můžou zahrnovat typ výrazu, hodnoty typů, hodnot vlastností a jejich kombinace. Porovnání výrazů se vzorem může být srozumitelnější než mnoho if porovnání. Prozkoumali jste některé vzory, které můžete použít k porovnávání výrazů. Existuje mnoho dalších způsobů, jak ve svých aplikacích použít porovnávání vzorů. Nejprve přejděte na web .NET a stáhněte si sadu .NET SDK, vytvořte projekt na svém počítači a pokračujte v kódování. Při zkoumání se můžete dozvědět více o porovnávání vzorů v jazyce C# v následujících článcích: