屬性與位置模式都測試價值的部分。 差別在於他們如何辨識這些部分:
- 屬性模式會命名要測試的屬性或欄位。
- 位置模式透過順序來識別價值。
解構會揭示一組有序的成分值。 元組本身就有元素順序;參見 解構元組。 另一種類型中,方法Deconstruct定義哪些元件值被暴露及其順序。
比較姓名與職位
以下性質模式測試兩個氣象讀數的命名性質,溫度值以攝氏度為單位:
static bool IsHotAndHumid(WeatherReading reading) =>
reading is { TemperatureC: > 30, HumidityPercent: > 70 };
sealed record WeatherReading(int TemperatureC, int HumidityPercent);
以下位置模式測試訊號值後接布林值:
static string GetCrossingInstruction(
PedestrianSignal signal, bool crossingIsClear) =>
(signal, crossingIsClear) switch
{
(PedestrianSignal.Walk, true) => "Cross now",
(PedestrianSignal.Walk, false) => "Wait for the crossing to clear",
_ => "Wait for the walk signal"
};
enum PedestrianSignal
{
Stop,
Walk
}
屬性模式以名稱 TemperatureC 和 HumidityPercent來識別其輸入。 交叉程式碼會從分開的 signal 和 crossingIsClear 值建立元組。 元組模式則依序識別這些值: signal 第一和 crossingIsClear 第二。 位置模式之所以強擬合,是因為這個新建立的元組只有兩個值,且它們的順序在交叉決策中具有明確的意義。
當成員名稱有助於說明測試時,請選擇屬性模式。 類別、結構與記錄的屬性模式通常較為清晰。 選擇位置模式時,順序已經賦予數值明顯意義。 位置模式在搭配元組時最有用,因為元組會將多個相關的值組合成一個具有固定順序的值。
以遞迴模式追蹤巢狀輸入
性質模式與位置模式是 遞迴模式:它們對每個屬性、域或位置套用另一種模式。 所選值成為該巢狀模式的輸入。
在 IsHotAndHumid 中,reading 運算式是屬性模式的輸入。 C# 在匹配前會評估該表達式。 圖案從所得物件中獲得兩個值:
- 關係模式
> 30會測試TemperatureC的值。 - 關係模式
> 70會測試HumidityPercent的值。
外部型別測試是可選的,遞迴模式子句也可以是空的。 例如,空屬性模式 { } 與任何非空值值相符。
性質與位置模式僅匹配非空值評估值。 當 null 屬於輸入域時,選擇一個遞迴模式,先檢查非空值:
static string DescribeNullableInput(object? value)
{
if (value is not { } nonNullValue)
{
return "No value";
}
return nonNullValue switch
{
DateTime => "Date",
string => "Text",
_ => "Another type"
};
}
輸入表達式為 value。 C# 會評估它,屬性 { } 模式會先測試所得值是否非空,然後將其指派給 nonNullValue。 接著,以下的切換表達式可以測試多種可能的執行時類型。 它 DateTime 和 string 型態模式沒有指定,因為方法只需識別每個型別,而不必捕捉其值。
當遞迴模式子句包含巢狀模式時,每個選擇的屬性、欄位或位置都會成為其巢狀模式的輸入。
當輸入表達式產生不同類型時,你可以在大括號前加一個型別測試。 你也可以使用成員路徑來測試巢狀屬性:
static string DescribeDate(object? value) =>
value switch
{
DateTime { Date.DayOfWeek:
DayOfWeek.Saturday or DayOfWeek.Sunday } => "Weekend date",
DateTime => "Weekday date",
null => "No date",
_ => "Not a date"
};
value 是輸入表達式。 C# 首先評估並測試所得值是否為 DateTime。 接著,Date 該屬性值會成為 DayOfWeek 成員存取的輸入。 最後,該 DayOfWeek 值成為測試兩個常數的邏輯模式的輸入。 當外部值具有指定型別,且沿成員路徑所需的所有物件皆非空時,匹配即告成功。
比較模式與分支語句
早期 DescribeDate 方法將四個結果表示為模式:
static string DescribeDate(object? value) =>
value switch
{
DateTime { Date.DayOfWeek:
DayOfWeek.Saturday or DayOfWeek.Sunday } => "Weekend date",
DateTime => "Weekday date",
null => "No date",
_ => "Not a date"
};
以下方法透過一系列命令式分支語句產生相同結果:
static string DescribeDateWithBranches(object? value)
{
if (value is DateTime date)
{
if (date.DayOfWeek == DayOfWeek.Saturday ||
date.DayOfWeek == DayOfWeek.Sunday)
{
return "Weekend date";
}
return "Weekday date";
}
if (value is null)
{
return "No date";
}
return "Not a date";
}
基於模式的版本則在多個分支測試值的類型與形狀時,將可能結果合併在一起。 命令式版本將每個測試與返回步驟明確化。 就其中一個狀況而言,兩種形式可能看起來相似。 隨著相關分支數量增加,模式能使替代方案更容易比較。