C# 在 C# 7.0 中引入了模式匹配。 自此之后,每个主要 C# 版本都扩展了模式匹配功能。 以下 C# 表达式和语句

支持模式匹配:


is 表达式

switch 语句

switch 表达式(在 C# 8.0 中引入)

在这些构造中,可将输入表达式与以下任一模式进行匹配:

声明模式:用于检查表达式的运行时类型,如果匹配成功,则将表达式结果分配给声明的变量。 在 C# 7.0 中引

入。

1、声明模式:用于检查表达式的运行时类型,如果匹配成功,则将表达式结果分配给声明的变量。 在 C# 7.0 中引

入。

2、类型模式:用于检查表达式的运行时类型。 在 C# 9.0 中引入。

3、常量模式:用于测试表达式结果是否等于指定常量。 在 C# 7.0 中引入。

4、关系模式:用于将表达式结果与指定常量进行比较。 在 C# 9.0 中引入。

5、属性模式:用于测试表达式的属性或字段是否与嵌套模式匹配。 在 C# 8.0 中引入。

6、位置模式:用于解构表达式结果并测试结果值是否与嵌套模式匹配。 在 C# 8.0 中引入。

7、var 模式:用于匹配任何表达式并将其结果分配给声明的变量。 在 C# 7.0 中引入。

8、弃元模式:用于匹配任何表达式。 在 C# 8.0 中引入。

9、逻辑模式:用于测试表达式是否与模式的逻辑组合匹配。 在 C# 9.0 中引入。

10、否定模式(C#9.0)

11、合取模式(C#9.0)

12、析取模式(C#9.0)

       13、括号模式(C#9.0)

 

大幅度反对法

类型模式

类型模式检查表达式的运行时类型是否与给定类型兼容



object greeting = "Hello, World!";
if (greeting is string)
{
Console.WriteLine(“声明模式”); // output: hello, world!
}


声明模式

 借助声明模式,还可声明新的局部变量。

当声明模式与表达式匹配时,将为该变量分配转换后的表达式结果,如以下示例所示:



object greeting = "Hello, World!";
if (greeting is string message)
{
Console.WriteLine(message.ToLower()); // output: hello, world!
}


 

常量模式

从 C# 7.0 开始,可使用常量模式来测试表达式结果是否等于指定的常量,如以下示例所示:



public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
1 => 12.0m,
2 => 20.0m,
3 => 27.0m,
4 => 32.0m,
0 => 0.0m,
_ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}",
nameof(visitorCount)),
};


在常量模式中,可使用任何常量表达式,例如:

integer 或 floating-point 数值文本

char 或 string 文本

布尔值 true 或 false

enum 值

声明常量字段或本地的名称

null

常量模式用于检查 null ,如以下示例所示:



if (input is null)
{
return;
}


编译器保证在计算表达式 x is null 时,不会调用用户重载的相等运算符 == 。

从 C# 9.0 开始,可使用否定 null 常量模式来检查非 NULL ,如以下示例所示:



if (input is not null)
{
// ...
}


有关详细信息,请参阅功能建议说明的常量模式部分。

 

关系模式

 从 C# 9.0 开始,可使用关系模式将表达式结果与常量进行比较,在关系模式中,

可使用关系运算符 < 、 > 、 <= 或 >= 中的任何一个。 关系模式的右侧部分必须是常数表达式。

常数表达式可以是 integer 、 floating-point、char 或 enum 类型。




Console.WriteLine(Classify(13)); // output: Too high
Console.WriteLine(Classify(double.NaN)); // output: Unknown
Console.WriteLine(Classify(2.4)); // output: Acceptable
static string Classify(double measurement) => measurement switch
{
< -4.0 => "Too low",
> 10.0 => "Too high",
double.NaN => "Unknown",
_ => "Acceptable",
};


要检查表达式结果是否在某个范围内,请将其与合取 and 模式匹配,如以下示例所示:



Console.WriteLine(GetCalendarSeason(new DateTime(2021, 3, 14))); // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 7, 19))); // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 2, 17))); // output: winter
static string GetCalendarSeason(DateTime date) => date.Month switch
{
>= 3 and < 6 => "spring",
>= 6 and < 9 => "summer",
>= 9 and < 12 => "autumn",
12 or (>= 1 and < 3) => "winter",
_ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
};


如果表达式结果为 null 或未能通过可为空或取消装箱转换转换为常量类型,则关系模式与表达式不匹配。


 

逻辑模式

 

从 C# 9.0 开始,可使用 not 、 and 和 or 模式连结符来创建以下逻辑模式:

否定 not 模式在否定模式与表达式不匹配时与表达式匹配。 下面的示例说明如何否定常量 null 模式来

检查表达式是否为非空值:



if (input is not null)
{
// ...
}


合取 and 模式在两个模式都与表达式匹配时与表达式匹配。 以下示例显示如何组合关系模式来检查值是

否在某个范围内:



Console.WriteLine(Classify(13)); // output: High
Console.WriteLine(Classify(-100)); // output: Too low
Console.WriteLine(Classify(5.7)); // output: Acceptable
static string Classify(double measurement) => measurement switch
{
< -40.0 => "Too low",
>= -40.0 and < 0 => "Low",
>= 0 and < 10.0 => "Acceptable",
>= 10.0 and < 20.0 => "High",
>= 20.0 => "Too high",
double.NaN => "Unknown",
};


 

析取 or 模式在任一模式与表达式匹配时与表达式匹配,如以下示例所示:



Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19))); // output: winter
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9))); // output: autumn
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11))); // output: spring
static string GetCalendarSeason(DateTime date) => date.Month switch
{
3 or 4 or 5 => "spring",
6 or 7 or 8 => "summer",
9 or 10 or 11 => "autumn",
12 or 1 or 2 => "winter",
_ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month:
{date.Month}."),
};


如前面的示例所示,可在模式中重复使用模式连结符。

and 模式连结符的优先级高于 or 。 要显式指定优先级,请使用括号,如以下示例所示:



static bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');


 

属性模式

 从 C# 8.0 开始,可使用属性模式来将表达式的属性或字段与嵌套模式进行匹配,如以下示例所示:

static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };

当表达式结果为非 NULL 且每个嵌套模式都与表达式结果的相应属性或字段匹配时,属性模式将与表达式匹配。

还可将运行时类型检查和变量声明添加到属性模式,如以下示例所示:



Console.WriteLine(TakeFive("Hello, world!")); // output: Hello
Console.WriteLine(TakeFive("Hi!")); // output: Hi!
Console.WriteLine(TakeFive(new[] { '1', '2', '3', '4', '5', '6', '7' })); // output: 12345
Console.WriteLine(TakeFive(new[] { 'a', 'b', 'c' })); // output: abc
static string TakeFive(object input) => input switch
{
string { Length: >= 5 } s => s.Substring(0, 5),
string s => s,
ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),
ICollection<char> symbols => new string(symbols.ToArray()),
null => throw new ArgumentNullException(nameof(input)),
_ => throw new ArgumentException("Not supported input type."),
};


 

属性模式是一种递归模式。 也就是说,可以将任何模式用作嵌套模式。 使用属性模式将部分数据与嵌套模式进

行匹配,如以下示例所示:

 



public record Point(int X, int Y);
public record Segment(Point Start, Point End);
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start: { Y: 0 } } or { End: { Y: 0 } };


 

前面的示例使用 C# 9.0 及更高版本中提供的两个功能: or 模式连结符和记录类型。有关详细信息,请参阅功能建议说明的属性模式部分。

 

 

位置模式


从 C# 8.0 开始,可使用位置模式来解构表达式结果并将结果值与相应的嵌套模式匹配,如以下示例所示:



public readonly struct 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);
static string Classify(Point point) => point switch
{
(0, 0) => "Origin",
(1, 0) => "positive X basis end",
(0, 1) => "positive Y basis end",
_ => "Just a point",
};


在前面的示例中,表达式的类型包含 Deconstruct 方法,该方法用于解构表达式结果。 还可将元组类型的表达式

与位置模式进行匹配。 这样,就可将多个输入与各种模式进行匹配,如以下示例所示:



static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate)
=> (groupSize, visitDate.DayOfWeek) switch
{
(<= 0, _) => throw new ArgumentException("Group size must be positive."),
(_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,
(>= 5 and < 10, DayOfWeek.Monday) => 20.0m,
(>= 10, DayOfWeek.Monday) => 30.0m,
(>= 5 and < 10, _) => 12.0m,
(>= 10, _) => 15.0m,
_ => 0.0m,
};


 


编程是个人爱好