模式匹配增强功能
一.switch表达式
通常情况下, switch 语句在其每个 case 块中生成一个值。 借助 Switch 表达式,可以使用更简洁的表达式语
法。 只有些许重复的 case 和 break 关键字和大括号。 以下面列出彩虹颜色的枚举为例:
public enum Rainbow { Red, Orange, Yellow, Green, Blue, Indigo, Violet }
如果应用定义了通过 R 、 G 和 B 组件构造而成的 RGBColor 类型,可使用以下包含 switch 表达式的方法,将Rainbow 转换为 RGB 值
public static RGBColor FromRainbow(Rainbow colorBand) => colorBand
switch {
Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
Rainbow.Green => new RGBColor(0x00, 0xFF, 0x00),
Rainbow.Blue => new RGBColor(0x00, 0x00, 0xFF),
Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
_ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};
这里有几个语法改进:
变量位于 switch 关键字之前。 不同的顺序使得在视觉上可以很轻松地区分 switch 表达式和 switch 语句。
将 case 和 : 元素替换为 => 。 它更简洁,更直观。
将 default 事例替换为 _ 弃元。
正文是表达式,不是语句
将其与使用经典 switch 语句的等效代码进行对比:
public static RGBColor FromRainbowClassic(Rainbow colorBand)
{
switch (colorBand)
{
case Rainbow.Red: return new RGBColor(0xFF, 0x00, 0x00);
case Rainbow.Orange: return new RGBColor(0xFF, 0x7F, 0x00);
case Rainbow.Yellow: return new RGBColor(0xFF, 0xFF, 0x00);
case Rainbow.Green: return new RGBColor(0x00, 0xFF, 0x00);
case Rainbow.Blue: return new RGBColor(0x00, 0x00, 0xFF);
case Rainbow.Indigo: return new RGBColor(0x4B, 0x00, 0x82);
case Rainbow.Violet: return new RGBColor(0x94, 0x00, 0xD3);
default: throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)); };
}
二.属性模式
借助属性模式,可以匹配所检查的对象的属性。 请看一个电子商务网站的示例,该网站必须根据买家地址计算销
售税。 这种计算不是 Address 类的核心职责。 它会随时间变化,可能比地址格式的更改更频繁。 销售税的金额
取决于地址的 State 属性。 下面的方法使用属性模式从地址和价格计算销售税:
public static decimal ComputeSalesTax(Address location, decimal salePrice)
=> location switch {
{ State: "WA" } => salePrice * 0.06M,
{ State: "MN" } => salePrice * 0.075M,
{ State: "MI" } => salePrice * 0.05M,
// other cases removed for brevity...
_ => 0M };
三.元组模式
一些算法依赖于多个输入。 使用元组模式,可根据表示为元组的多个值进行切换。 以下代码显示了游戏“rock,
paper, scissors(石头剪刀布)”的切换表达式::
public static string RockPaperScissors(string first, string second) => (first, second)
switch { ("rock", "paper") => "rock is covered by paper. Paper wins.",
("rock", "scissors") => "rock breaks scissors. Rock wins.",
("paper", "rock") => "paper covers rock. Paper wins.",
("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
("scissors", "rock") => "scissors is broken by rock. Rock wins.",
("scissors", "paper") => "scissors cuts paper. Scissors wins.",
(_, _) => "tie" };
四.位置模式
某些类型包含 Deconstruct 方法,该方法将其属性解构为离散变量。 如果可以访问 Deconstruct 方法,就可以使
用位置模式检查对象的属性并将这些属性用于模式。 考虑以下 Point 类,其中包含用于为 X 和 Y 创建离散变
量的 Deconstruct 方法:
public class Point
{ public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
}
此外,请考虑以下表示象限的各种位置的枚举:
public enum Quadrant { Unknown, Origin, One, Two, Three, Four, OnBorder }
下面的方法使用位置模式来提取 x 和 y 的值。 然后,它使用 when 子句来确定该点的 Quadrant :
static Quadrant GetQuadrant(Point point) => point switch { (0, 0) => Quadrant.Origin, var (x, y) when x > 0 && y > 0 => Quadrant.One, var (x, y) when x < 0 && y > 0 => Quadrant.Two, var (x, y) when x < 0 && y < 0 => Quadrant.Three, var (x, y) when x > 0 && y < 0 => Quadrant.Four, var (_, _) => Quadrant.OnBorder, _ => Quadrant.Unknown };
当 x 或 y 为 0(但不是两者同时为 0)时,前一个开关中的弃元模式匹配。 Switch 表达式必须要么生成值,要么
引发异常。 如果这些情况都不匹配,则 switch 表达式将引发异常。 如果没有在 switch 表达式中涵盖所有可能的
情况,编译器将生成一个警告。
可在此模式匹配高级教程中探索模式匹配方法。 有关位置模式的详细信息,请参阅模式的位置模式部分。