次の方法で共有


データをパターンと照合する

このチュートリアルでは、パターン マッチングを使用して C# のデータを検査する方法について説明します。 少量のコードを記述した後、そのコードをコンパイルして実行します。 このチュートリアルには、C# のさまざまな種類の型を調べる一連のレッスンが含まれています。 これらのレッスンでは、C# 言語の基礎について説明します。

ヒント

コード スニペット ブロックに [実行] ボタンが含まれている場合、そのボタンによって対話型ウィンドウが開くか、対話型ウィンドウ内の既存のコードが置き換えられます。 スニペットに [実行] ボタンが含まれていない場合は、コードをコピーして現在の対話型ウィンドウに追加できます。

前のチュートリアルでは、組み込みの型や、タプルやレコードとして定義する型を示しました。 これらの型のインスタンスは 、パターンに対してチェックできます。 インスタンスがパターンと一致するかどうかによって、プログラムが実行するアクションが決まります。 次の例では、型名の後に ? があります。 このシンボルを使用すると、この型の値を null にすることができます (たとえば、 bool?truefalse 、または nullできます)。 詳細については、「 Null 許容値型」を参照してください。 まず、パターンの使用方法を調べてみましょう。

値を一致させる

このチュートリアルのすべての例では、一連の銀行取引をコンマ区切り値 (CSV) 入力として表すテキスト入力を使用します。 各サンプルでは、 is または switch 式を使用して、レコードをパターンと照合できます。 この最初の例では、,文字の各行を分割し、式を使用して最初の文字列フィールドを値 "DEPOSIT" または "WITHDRAWAL" とisします。 一致すると、トランザクション金額が現在の口座残高に加算または差し引かれます。 動作を確認するには、[実行] ボタンを押します。

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

出力を確認します。 各行が処理されているのは、最初のフィールドのテキストの値を比較することで確認できます。 上記のサンプルは、2 つの==値が等しいことをテストするために、string演算子を使用して同様に構築できます。 変数と定数の比較は、パターン マッチングの基本的な構成要素です。 パターン マッチングの一部である構成要素の詳細を見てみましょう。

列挙型の一致条件

パターン マッチングのもう 1 つの一般的な用途は、 enum 型の値に一致することです。 次のサンプルでは、入力レコードを処理して タプル を作成します。最初の値は預金または出金をメモする enum 値です。 2 番目の値は、トランザクションの値です。 動作を確認するには、[実行] ボタンを押します。

警告

コピーして貼り付けないでください。 次のサンプルを実行するには、対話型ウィンドウをリセットする必要があります。 間違えた場合、ウィンドウがハングし、続行するにはページを更新する必要があります。

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
}

前の例では、 if ステートメントを使用して、 enum 式の値も確認します。 パターン マッチングの別の形式では、 switch 式が使用されます。 その構文とその使用方法を見てみましょう。

徹底的な一致 switch

一連の if ステートメントでは、一連の条件をテストできます。 ただし、コンパイラは、一連の if ステートメントが 網羅的 であるか、後の if 条件が以前の条件によって サブスム化されているか を確認できません。 switch式を使用すると、これらの両方の特性が確実に満たされるため、アプリのバグが少なくなります。 試して実験してみましょう。 次のコードをコピーします。 対話型ウィンドウの 2 つの if ステートメントを、コピーした switch 式に置き換えます。 コードを変更したら、対話型ウィンドウの上部にある [実行] ボタンを押して、新しいサンプルを実行します。

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

コードを実行すると、同じように動作することがわかります。 包括を示すには、次のスニペットに示すようにスイッチ アームを並べ替えます。

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

スイッチ アームの順序を変更したら、[実行] ボタンを押します。 コンパイラは、 _ を持つ arm がすべての値と一致するため、エラーを発行します。 その結果、TransactionType.Withdrawal を持つコードの最後の部分は決して動作しません。 コンパイラは、コードに何かが間違っていることを通知します。

switch式でテストされた式にスイッチ アームと一致しない値が含まれている可能性がある場合、コンパイラは警告を発行します。 一部の値が条件に一致しない可能性がある場合、 switch 式は 完全ではありません。 コンパイラは、入力の一部の値がスイッチ アームのいずれとも一致しない場合にも警告を発行します。 たとえば、 _ => 0.0,の行を削除した場合、無効な値は一致しません。 実行時に失敗します。 .NET SDK をインストールし、環境にプログラムをビルドしたら、この動作をテストできます。 オンライン エクスペリエンスでは、出力ウィンドウに警告は表示されません。

型パターン

このチュートリアルを完了するために、もう 1 つの構成要素とパターン マッチング ( 型パターン) を調べてみましょう。 型パターンは、実行時に式をテストして、指定された型であるかどうかを確認します。 型テストは、 is 式または switch 式で使用できます。 2 つの方法で現在のサンプルを変更してみましょう。 まず、タプルの代わりに、トランザクションを表すレコード型 DepositWithdrawal を作成してみましょう。 対話型ウィンドウの下部に次の宣言を追加します。

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

次に、 Main メソッドの後にこのメソッドを追加してテキストを解析し、一連のレコードを返します。

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

最後に、foreach メソッドのMain ループを次のコードに置き換えます。

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

次に、[実行] ボタンを押して結果を表示します。 この最終バージョンでは、 入力が型に対してテストされます。

パターン マッチングは、式と特性を比較するためのボキャブラリを提供します。 パターンには、式の型、型の値、プロパティ値、およびそれらの組み合わせを含めることができます。 パターンに対する式の比較は、複数の if 比較よりも明確になる場合があります。 式の照合に使用できるパターンの一部について説明しました。 アプリケーションでパターン マッチングを使用するには、さらに多くの方法があります。 まず、 .NET サイト にアクセスして .NET SDK をダウンロードし、コンピューター上にプロジェクトを作成し、コーディングを続けます。 C# でのパターン マッチングの詳細については、次の記事を参照してください。