共用方式為


比對模式的數據

本教學課程會教導您如何使用模式比對來檢查 C# 中的數據。 您撰寫少量的程式代碼,然後編譯並執行該程序代碼。 本教學課程包含一系列課程,可探索 C# 中不同類型的類型。 這些課程會教您 C# 語言的基本概念。

小提示

當代碼段區塊包含 [執行] 按鈕時,該按鈕會開啟互動式視窗,或取代互動式視窗中的現有程序代碼。 當程式碼片段不包含 [執行] 按鈕時,您可以複製程式代碼並將其加入目前的互動式視窗。

上述教學課程示範您定義為 Tuple 或記錄的內建類型和類型。 您可以針對 模式檢查這些類型的實例。 實例是否符合模式,會決定程序採取的動作。 在以下的範例中,您會注意到類型名稱之後的 ?。 此符號可讓此類型的值成為 Null(例如, bool? 可以是 truefalsenull。 如需詳細資訊,請參閱 可為 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}");
    }
}

檢查輸出。 您可以藉由比較第一個字段中的文字值,來查看每一行的處理方式。 上述範例可以使用 運算符類似建構 == ,以測試兩個 string 值是否相等。 比較變數與常數是模式比對的基本建置組塊。 讓我們探索屬於模式比對一部分的建置組塊。

列舉相符專案

模式比對的另一個常見用途是比對型別 enum 的值。 下一個範例會處理輸入記錄,以建立 Tuple ,其中第一個 enum 值是記下存款或取款的值。 第二個值是交易的值。 若要查看運作,請按 [執行] 按鈕:

警告

請勿複製並貼上。 互動式窗口必須重設,才能執行下列範例。 如果您犯了錯誤,視窗會停止回應,需要重新整理頁面才能繼續。

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 可確保符合這兩個特性,這會導致應用程式中的 Bug 較少。 讓我們試試看並實驗。 複製下列程序代碼。 將互動式視窗中的兩個if語句替換為您所複製的switch 表達式。 修改程式代碼之後,請按互動式視窗頂端的 [執行] 按鈕來執行新的範例。

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

當您執行程式代碼時,您會看到其運作方式相同。 若要示範 包含,請按照下列代碼片段所示重新安排 switch 的分支。

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

重新排列切換臂之後,請按 [執行] 按鈕。 編譯程式會發出錯誤,因為 arm 的 _ 匹配每個值。 因此,最後一段 TransactionType.Withdrawal 從未被執行。 編譯程式會告訴您程式代碼中有問題。

如果表達式中測試的 switch 表達式可能包含不符合任何參數臂的值,編譯程式就會發出警告。 如果某些值可能不符合任何條件,則 switch 表達式並不 詳盡。 如果輸入的某些值不符合任何切換臂,編譯程式也會發出警告。 例如,如果您移除包含 _ => 0.0, 的行,那麼任何無效的值都無法匹配。 在運行時,這會失敗。 在環境中安裝 .NET SDK 和建置程序之後,您就可以測試此行為。 在線體驗不會在輸出視窗中顯示警告。

類型模式

若要完成本教學課程,讓我們再探索一個建置組塊來比對模式: 類型模式類型模式會在運行時間測試表示式,以查看其是否為指定的類型。 您可以使用類型測試搭配 is 表示式或 switch 表示式。 讓我們以兩種方式修改目前的範例。 首先,讓我們建立代表交易的 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# 中的模式比對: