Tip
本文是已了解至少一种编程语言并正在学习 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 中,temperature is < 0 是模式输入表达式。 C# 会对其进行评估,关系模式 < 0 会测试生成的值。 在 switch 分支 < 0 => "Freezing" 中,switch 前面的表达式提供输入值,因此该模式只包含 < 0。
表达式可以与变量threshold进行比较temperature。 关系模式操作数必须是编译时常量,因此当比较值是变量时,请使用关系表达式。 当比较值为常量时,这两种形式都可行。
当右操作数为常量时,主要根据可读性来选择。 关系表达式通常只包含一次直接比较。 关系模式可与其他模式组合,当多个范围映射到切换结果时,它会自然而然地适应。
将条件与逻辑模式组合在一起
逻辑模式使用模式运算符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# 指定以下绑定顺序:
notandor
以下测试接受优先级 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 检查单独的值。 当条件需要方法调用或模式语法未明确表达的布尔表达式时,防护也更可取。
当关系模式和逻辑模式能更清晰地体现输入允许的形状或值时,请使用它们,尤其是在 switch 的多个分支中。 当普通布尔表达式能更简洁地直接表达条件时,请使用普通布尔表达式。 当切换选择取决于单独的值,或取决于更适合用布尔表达式表示的条件时,使用 when 防护。