Бөлісу құралы:


Руководство. Использование C# для сопоставления данных с шаблонами

В этом руководстве описано, как использовать сопоставление шаблонов для проверки данных в C#. Вы пишете небольшие объемы кода, а затем компилируете и запускаете этот код. В этом руководстве содержится ряд уроков, которые изучают различные типы шаблонов, поддерживаемых C#. Эти уроки учат вас основам языка C#.

Изучив это руководство, вы:

  • Запустите пространство кода GitHub с помощью среды разработки C#.
  • Тестируйте данные для дискретных значений.
  • Соотносить перечисляемые данные со значением.
  • Создайте исчерпывающие совпадения с помощью switch выражений.
  • Сопоставление типов с использованием шаблонов типов.

Предпосылки

У вас должно быть одно из следующих элементов:

Сопоставление значения

В предыдущих руководствах показаны встроенные типы и типы, которые определяются как кортежи или записи. Вы можете проверить экземпляры этих типов на соответствие шаблону. Совпадает ли экземпляр с шаблоном, определяет действия, выполняемые программой. В приведенных ниже примерах вы увидите ? после имен типов. Этот символ позволяет значению этого типа иметь значение NULL (например, bool? может быть true, falseили null). Дополнительные сведения см. в разделе "Типы значений, допускающих значение NULL". Начнем с изучения способа использования шаблонов.

Откройте окно браузера в пространствах кода GitHub. Создайте новое пространство кода из шаблона .NET. Если вы выполнили другие уроки в этой серии, вы можете открыть это кодовое пространство.

  1. При загрузке пространства кода создайте новый файл в папке учебников с именем patterns.cs.

  2. Откройте новый файл.

  3. Во всех примерах в этом руководстве используются текстовые входные данные, представляющие ряд банковских транзакций в виде входных данных, разделенных запятыми (CSV). В каждом из образцов каждую запись можно сопоставить с шаблоном с помощью выражения is или switch. Этот первый пример разбивает каждую строку на , символ, а затем сопоставляет первое строковое поле со значением "ДЕПОЗИТ" или "ВЫВОД" с помощью is выражения. При совпадении сумма транзакции добавляется или вычитается из текущего баланса счета. Чтобы увидеть его работу, добавьте следующий код в 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. Затем введите следующий текст в окне терминала:

    cd tutorials
    dotnet patterns.cs
    
  5. Проверьте выходные данные. Вы можете увидеть, что каждая строка обрабатывается, сравнивая значение текста в первом поле.

Можно аналогично создать предыдущий пример с помощью == оператора для проверки того, что два string значения равны. Сравнение переменной с константой является основным стандартным блоком для сопоставления шаблонов. Давайте рассмотрим больше основных элементов, которые являются частью сопоставления шаблонов.

Совпадения элементов перечисления

Другой распространенный способ сопоставления шаблонов — сопоставление значений enum типа. Следующий пример обрабатывает входные записи, чтобы создать кортеж, где первое значение является enum значением, которое отмечает депозит или вывод. Второе значение — это значение транзакции.

  1. Добавьте следующий код в конец исходного файла. Он определяет перечисление TransactionType :

    public enum TransactionType
    {
        Deposit,
        Withdrawal,
        Invalid
    }
    
  2. Добавьте функцию для анализа банковской транзакции в кортеж, содержащий тип транзакции и значение транзакции. Добавьте следующий код перед объявлением 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. Добавьте новый цикл для обработки данных транзакции с помощью вами объявленного перечисления TransactionType.

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

В предыдущем примере также используется if инструкция для проверки значения enum выражения. Другая форма сопоставления шаблонов использует switch выражение. Давайте рассмотрим этот синтаксис и как его можно использовать.

Исчерпывающие совпадения с switch

Ряд if инструкций может протестировать ряд условий. Но компилятор не может определить, являются ли ряд операторов ifисчерпывающими, или если более поздние if условия охвачены предыдущими условиями. Исчерпывающим образом означает, что один из ifelse предложений в серии тестов обрабатывает все возможные входные данные. Если ряд инструкций if является исчерпывающим, все возможные входные данные удовлетворяют по крайней мере одному if или else предложению. Подстановочное правило означает, что позднее if или else условие не может быть достигнуто, так как предыдущие if или else условия соответствуют всем возможным входным данным. Например, в следующем примере кода одно предложение никогда не совпадает:

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

Условие else if никогда не выполняется, так как любое число меньше 10 также меньше 20. Выражение switch гарантирует выполнение обоих этих характеристик, что приводит к меньшим ошибкам в приложениях. Давайте попробуем и поэкспериментируем.

  1. Скопируйте следующий код. Замените две инструкции if в вашем foreach цикле на скопированное выражение switch.

    currentBalance += transaction switch
    {
        (TransactionType.Deposit, var amount) => amount,
        (TransactionType.Withdrawal, var amount) => -amount,
        _ => 0.0,
    };
    
  2. Введите dotnet patterns.cs в окне терминала, чтобы запустить новый пример.

    При запуске кода вы увидите, что он работает так же.

  3. Чтобы продемонстрировать подсумпцию, переставьте ветви переключателя, как показано в следующем фрагменте:

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

    После переупорядочивания рычагов переключателя введите dotnet patterns.cs в окне терминала. Компилятор выдает ошибку, потому что ветвь с _ совпадает с каждым возможным значением. В результате, этот последний сегмент с TransactionType.Withdrawal никогда не выполняется. Компилятор сообщает, что в коде что-то не так.

    Компилятор выдает предупреждение, если выражение, проверенное в switch выражении, может содержать значения, которые не соответствуют ни одной ветви switch. Если некоторые значения не могут соответствовать любому условию, switch выражение не является исчерпывающим. Компилятор также выдает предупреждение, если некоторые значения входных данных не соответствуют ни одной из ветвей оператора switch.

  4. Удалите строку с _ => 0.0,, чтобы недопустимые значения не совпадали.

  5. Введите dotnet patterns.cs, чтобы просмотреть результаты.

    Компилятор выдает предупреждение. Тестовые данные допустимы, поэтому программа работает. Однако любые недопустимые данные могут привести к сбою во время выполнения.

Шаблоны типов

Для завершения работы с этим руководством изучите еще один стандартный блок для сопоставления шаблонов: типовой шаблон. Шаблон типа проверяет выражение во время выполнения, чтобы узнать, является ли он указанным типом. С выражением is или switch выражением можно использовать тест типа. Измените текущий пример двумя способами. Во-первых, вместо кортежа создайте типы записей Deposit и Withdrawal, которые представляют транзакции.

  1. Добавьте следующие объявления в конце файла кода:

    public record Deposit(double Amount, string description);
    public record Withdrawal(double Amount, string description);
    
  2. Добавьте этот метод непосредственно перед объявлением TransactionType перечисления. Он анализирует текст и возвращает ряд записей:

    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. Добавьте следующий код после последнего foreach цикла:

    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. Введите dotnet patterns.cs в окне терминала, чтобы увидеть результаты. Эта окончательная версия проверяет входные данные по типу.

Сопоставление шаблонов предоставляет словарь для сравнения выражения с характеристиками. Шаблоны могут включать тип выражения, значения типов, значений свойств и сочетаний этих выражений. Сравнение выражений с шаблоном может быть более четким, чем несколько if сравнений. Вы изучили некоторые шаблоны, которые можно использовать для сопоставления выражений. Существует множество способов использования сопоставления шаблонов в приложениях. При изучении вы можете узнать больше о сопоставлении шаблонов в C# в следующих статьях:

Очистка ресурсов

GitHub автоматически удаляет пространство Codespace через 30 дней бездействия. Вы завершили все уроки в этой серии. Чтобы удалить ваш Codespace, откройте окно браузера и перейдите к вашим Codespaces. В окне отобразится список ваших codespaces. Выберите три точки (...) в записи для пространства кода учебника для обучения и выберите удалить.