關聯型、邏輯型與括號型態

小提示

本文屬於 基礎部分, 適合已經至少懂一種程式語言並正在學習 C# 的開發者。 如果你不熟悉模式,可以先從 模式比對概觀 開始。 完整語言規則請參閱語言參考中的 關聯模式 與 邏輯模式 。

關係型與邏輯型態描述範圍、替代方案與排除。 以下方法將兩者結合以分類溫度:

static string ClassifyTemperature(int temperature) =>
    temperature switch
    {
        < 0 => "Below freezing",
        >= 18 and <= 24 => "Comfortable",
        (>= 0 and < 10) or > 30 => "Far outside the comfortable range",
        _ => "Cool or warm"
    };

表達 temperature 式就是模式輸入。 C# 只會評估該運算式一次,而每個 switch 分支都會比對其結果值。 這些手臂展示了以下測試:

  • < 0 測試其中一個邊界。
  • >= 18 and <= 24 測試範圍。
  • (>= 0 and < 10) or > 30 測試兩種替代射程。

本文展示了兩種模式與命令條件,讓你能學習每種形式,並比較它們如何表達相同的決策。 單一狀況在兩種形式下都可能相似。 模式能讓一系列相關分支更容易閱讀,因為將選擇與結果並列。 選擇最容易理解程式碼的形式。

比較數值與關係型態

關聯 型態 會透過使用 <、 >、 <=、 或 >=來比較其模式輸入與編譯時常數。 編譯時常數是編譯器在編譯程式時可以評估的值。 數值和字元常值,以及屬於相容之數值或字元型別的 const 變數,都是典型範例。 一般的變數、屬性、方法呼叫和 static readonly 欄位不是編譯時的常數。 在開頭的範例中,>= 18 和 <= 24 都會測試相同的已求值 temperature 值。

相同的關係符號可以出現在普通表達式或圖案中。 以下範例以溫度示範這兩種格式:

static void ShowExpressionAndPattern(int temperature, int threshold)
{
    bool belowThreshold = temperature < threshold;
    bool belowFreezing = temperature is < 0;

    string description = temperature switch
    {
        < 0 => "Freezing",
        0 => "Freezing point",
        > 0 => "Above freezing"
    };

    Console.WriteLine(
        $"Below threshold: {belowThreshold}; " +
        $"below freezing: {belowFreezing}; {description}");
}

temperature < threshold 是一個 關係表達式。 它會評估兩個運算元並產生一個 bool。 任一運算元都可以是非恆定的表達式。

在 temperature is < 0中, temperature 是模式輸入表達式。 C# 會評估它,而關聯模式 < 0 則會測試所得值。 在 switch arm < 0 => "Freezing" 中,switch 前面的運算式提供輸入,因此該模式只包含 < 0。

該表達式可與 temperature 變數 threshold比較。 關聯模式運算元必須是編譯時常數,因此當比較值為變數時,請使用關聯式表達式。 當比較值為固定時,任一形式皆可運作。

當右運算元為常數時,主要以可讀性為考量來選擇。 關係表達式通常適合一個直接比較。 關係型態會與其他型態組成,當多個區間映射到切換結果時,自然契合。

將條件與邏輯模式結合

邏輯模式使用模式運算子 and、or 和 not 來結合或否定模式:

  • 當兩個巢狀模式都相符時,and 模式就會相符。
  • 當任一巢狀模式符合時,or 模式就會符合。
  • not 模式會在其巢狀模式失敗時成功。

開頭的例子用 and 來描述一個範圍並 or 描述替代方案。 not模式可以排除某個值,例如 status is not Status.Complete。 以下方法展示兩種形式,讓你能學習它們的語法並比較它們如何表達同一測試:

static bool IsWeekendPattern(DayOfWeek day) =>
    day is DayOfWeek.Saturday or DayOfWeek.Sunday;

static bool IsWeekendImperative(DayOfWeek day) =>
    day == DayOfWeek.Saturday || day == DayOfWeek.Sunday;

該模式形式使用兩個常數模式,並由 or連接 。 命令式形式使用兩個相等性運算式,並以條件 OR 運算子 || 連接。 兩種形式都簡潔且清楚,適用於此單一條件。 選擇最適合周遭法規的形態。 模式通常會釐清 中 switch多個相關選擇,如開頭範例所示。

模式運算子形成模式而非布林表達式: and 對應模式合取、 or 模式替代方案及 not 模式否定。 布林表達式使用 &&、 ||、 !和 。 當多種圖案選擇結果相同時,選擇 or 。 當表達排除的模式比列出所有可接受的值更清楚時,請選擇 not。

括號內的群組模式

括號中的圖案使用括號來顯示或改變巢狀圖案的分組方式。 綁定決定運算子會將哪些模式中的運算元歸為一組,類似於未寫出括號時的隱式分組。 C# 規定了以下綁定順序:

  1. not
  2. and
  3. or

以下測試接受優先順序1至3或特殊優先順序9:

static bool IsAcceptedPriority(int priority) =>
    priority is (>= 1 and <= 3) or 9;

編譯器會先將 or 分組,再處理 and。 括號明確表示預期的分組,且兩種選項易於辨識:1 到 3 或 9 的範圍。 為了方便閱讀,當模式混合 and 和 or時 not ,或應用於複合模式時,請使用括號。 括號也可以改變預設分組,例如 not (>= 1 and <= 3)。

巢狀模式的執行時檢查順序未明確說明,且模式運算子遵循模式匹配規則,而非短路布林規則。 寫出巢狀模式,使其結果不受檢查順序影響。

when用護衛處理另一個病症

邏輯模式在巢狀模式描述輸入值本身時效果最佳。 when護線是標籤或開關臂上的case額外布林條件。 當決策也依賴與模式輸入不同的資訊時,使用護衛。

以下警告依溫度及獨立 isOutdoors 數值而定:

static string GetHeatWarning(int temperature, bool isOutdoors) =>
    temperature switch
    {
        > 35 when isOutdoors => "High heat outdoors",
        > 35 => "High heat",
        _ => "No heat warning"
    };

關係模式> 35描述了輸入。temperature 守衛 when isOutdoors 會檢查另一個數值。 當條件需要方法呼叫或布林運算式(但模式語法無法清楚表達)時,guard 也會被推薦。

當關聯模式和邏輯模式能讓輸入所允許的形式或值更容易看出時,請使用這些模式,尤其是在 switch 的多個分支中。 當它陳述直接條件更簡單時,使用普通的布林表達式。 當交換選擇依賴於獨立值或更適合用布林表達式表達的條件時,請使用 when 守衛。

另請參閱