C# - Switch Expressions (Pattern Matching)
在 C# 中,switch expressions 是 pattern matching 的一种形式,它允许我们根据表达式中第一个匹配的 pattern 执行操作。C# 中的 switch expression 是 传统 switch statement 的现代替代方案,在 C# 8.0 中引入。与传统 switch statement 相比,它提高了可读性和简洁性。
它允许我们创建简单、基于表达式的 pattern-matching 逻辑,并返回一个值。它特别有助于简化条件逻辑,替换复杂的 if-else 或 switch statement。
Switch expressions 与 pattern matching 无缝协作,不仅可以匹配常量值,还可以匹配类型、范围、关系 pattern 和复杂条件。
让我们通过 C# 代码比较传统 switch statement 与 switch expression −
传统 Switch Statement 与 Switch Expression
传统 Switch Statement − 在下面的代码中,我们使用 switch statement 来显示给定的数字对应工作日还是周末。
using System;
class Program {
static void Main(){
int dayNumber = 4;
Console.WriteLine($"Day Number: {dayNumber}");
string dayType = GetDayType(dayNumber);
Console.WriteLine($"Day Type: {dayType}");
}
static string GetDayType(int dayNumber){
string result;
switch (dayNumber){
case 1:
case 7:
result = "Weekend";
break;
case 2:
case 3:
case 4:
case 5:
case 6:
result = "Weekday";
break;
default:
result = "Invalid Day";
break;
}
return result;
}
}
以上代码的输出如下 −
Day Number: 4 Day Type: Weekday
Switch Expression:在下面的代码中,我们使用 switch expression 来显示给定的数字对应工作日还是周末。
using System;
class Program {
static void Main(){
int dayNumber = 4;
string dayType = GetDayType(dayNumber);
Console.WriteLine($"Day Number: {dayNumber}");
Console.WriteLine($"Day Type: {dayType}");
}
static string GetDayType(int dayNumber) =>
dayNumber switch {
1 or 7 => "Weekend",
>= 2 and <= 6 => "Weekday",
_ => "Invalid Day"
};
}
输出如下 −
Day Number: 4 Day Type: Weekday
现在,在比较了传统 switch statement 和 switch expression 之后,我们了解到 switch expression 优于 switch statement,因为它使代码更简洁、可读,并支持 pattern matching。让我们进一步了解 switch expression。
使用 Switch Expression 的优势
使用 switch expression 的优势如下 −
- 它更简洁、可读、更易理解,且耗时更少。
- 它直接返回一个值。
- 它使用 pattern matching 语法。
- 它消除了重复的 break 和 return 关键字。
Switch Expression 的声明
在 C# 中,switch expression 使用简洁的基于表达式的声明风格,如下所示 −
var result = input switch {
pattern1 => expression1,
pattern2 => expression2,
_ => defaultExpression
};
上述语法包含以下变量和参数 −
- input − 要评估的值或变量。
- pattern − 匹配条件(常量、关系或类型 pattern)。
- expression − 当 pattern 匹配时返回的值或结果。
- _(discard pattern) − 如果没有其他 pattern 匹配,它相当于 default case。
Switch 表达式中的模式匹配
Switch 表达式支持多种模式,用于强大的匹配逻辑。
- 常量模式
- 类型模式
- 关系模式
- 逻辑模式 (and, or, not)
- 属性模式
- 位置模式 (解构)
C# 常量模式
常量模式 是一种更简单的方式,用于将值与固定常量进行比较。它类似于使用 "==" 操作符检查表达式是否等于特定常量值。
在常量模式中,你可以使用任何常量表达式,例如 −
integer或floating-point数值字面量- 一个
char - 一个
string字面量。 - 布尔值
true或false - 一个
enum值 - 已声明的
const字段或本地变量的名称 - null
表达式必须是能够转换为常量类型的类型。
常量模式的示例
在以下示例中,我们在 switch 表达式中使用 常量模式 将温度与常量值进行比较 −
using System;
class Program {
static void Main(){
int temperature = 25;
string condition = GetWeatherCondition(temperature);
Console.WriteLine($"Temperature: {temperature} deg C");
Console.WriteLine($"Weather Condition: {condition}");
}
// constant pattern
static string GetWeatherCondition(int temperature) =>
temperature switch{
0 => "Freezing",
25 => "Pleasant",
40 => "Hot",
_ => "Unknown"
};
}
以下是输出 −
Temperature: 25 deg C Weather Condition: Pleasant
C# 类型模式
类型模式用于在 switch 表达式中检查对象的运行时类型,并在匹配分支中可选地将其用作该类型。
它帮助我们根据变量或表达式的类型决定执行什么操作。例如,它是 int、string、double,还是自定义 class。
为什么使用类型模式
- 根据对象的类型执行不同的操作。
- 避免手动类型检查,使用 is、as 或强制转换 ((int)obj)。
- 使代码更简洁、更安全(无无效类型转换)。
类型模式的示例
在这个示例中,switch 表达式使用类型模式在运行时检查对象元素的类型 −
using System;
class Program {
static void Main(){
object value = 3.14;
string result = CheckObjectType(value);
Console.WriteLine($"Value: {value}");
Console.WriteLine($"Type: {result}");
}
static string CheckObjectType(object obj) =>
obj switch {
int => "Integer Type",
string => "String Type",
double => "Double Type",
_ => "Unknown Type"
};
}
以下是输出 −
Value: 3.14 Type: Double Type
C# 关系模式
我们使用关系模式将表达式结果与常量进行比较。
在关系模式中,我们可以使用任何关系运算符,如 <、>、<= 或 >=. 关系模式右侧必须是常量表达式。常量表达式可以是 integer、floating-point、char 或 enum 类型。
关系模式的示例
以下是 关系模式 的示例,它将表达式结果与常量进行比较。
using System;
class Program {
static void Main(){
Console.WriteLine(Classify(13));
Console.WriteLine(Classify(double.NaN));
Console.WriteLine(Classify(2.4));
}
static string Classify(double measurement) => measurement switch{
< -4.0 => "Too low",
> 10.0 => "Too high",
double.NaN => "Unknown",
_ => "Acceptable",
};
}
以下是输出 −
Too high Unknown Acceptable
如果表达式结果为 null,或无法通过可空转换或取消装箱转换转换为常量的类型,则关系模式不会匹配该表达式。
C# 逻辑模式 (and, or, not)
逻辑模式允许我们在 switch 表达式中使用 and、or 和 not 组合多个条件。它使你的模式匹配更灵活和富有表现力。
我们使用逻辑模式组合多个条件,而无需编写嵌套的 if-else 语句。它与关系模式和类型模式配合良好。
逻辑模式的示例
以下是输出 −
在以下示例中,我们使用逻辑模式(and 操作符)显示年龄类别,而无需传递 if-else 语句。
using System;
class Program {
static void Main(){
int age = 15;
string category = GetAgeCategory(age);
Console.WriteLine($"Age: {age}");
Console.WriteLine($"Category: {category}");
}
static string GetAgeCategory(int age) =>
age switch {
< 13 => "Child",
>= 13 and < 20 => "Teenager",
>= 20 and < 60 => "Adult",
>= 60 => "Senior"
};
}
以下是输出 −
Age: 15 Category: Teenager
C# 属性模式
我们使用 属性模式 将表达式的属性或字段与特定条件(嵌套模式)进行匹配。例如 −
static bool IsConferenceDay(DateTime date) =>
date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
它检查表达式是否为 non-null,以及每个嵌套模式是否匹配表达式的相应属性或字段。如果所有条件都满足,则属性模式被视为匹配。
我们还可以向属性模式添加运行时类型检查和变量声明。
属性模式的示例
这是一个简单明了的示例,展示了如何在属性模式中添加运行时类型检查和变量声明 −
using System;
class Program {
static void Main(){
object person = new Person { Name = "Aman", Age = 25 };
string result = GetPersonInfo(person);
Console.WriteLine(result);
}
static string GetPersonInfo(object obj) =>
obj switch {
// Type check, property pattern, variable declaration
Person { Name: var name, Age: var age } => $"Person: {name}, Age: {age}",
_ => "Unknown object"
};
}
class Person {
public string Name { get; set; }
public int Age { get; set; }
}
以下是输出 −
Person: Alice, Age: 25
C# 位置模式
位置模式用于解构表达式的结果,并将单个值与相应的嵌套模式进行匹配。
位置模式的示例
在以下示例中,我们将看到位置模式如何用于解构表达式结果。
using System;
public struct Point {
public int X { get; }
public int Y { get; }
// Constructor to initialize X and Y
public Point(int x, int y){
X = x;
Y = y;
}
// Deconstruct method allows splitting Point into (x, y)
public void Deconstruct(out int x, out int y){
x = X;
y = Y;
}
}
class Program{
static void Main(){
var p1 = new Point(0, 0);
var p2 = new Point(1, 0);
var p3 = new Point(3, 4);
Console.WriteLine(Classify(p1));
Console.WriteLine(Classify(p2));
Console.WriteLine(Classify(p3));
}
// Using positional pattern to match coordinates
static string Classify(Point point) => point switch {
(0, 0) => "Origin",
(1, 0) => "Positive X axis point",
(0, 1) => "Positive Y axis point",
_ => "Just a point"
};
}
以下是 输出 −
Origin Positive X axis point Just a point
在上述示例中,表达式的类型包含 Deconstruct 方法,该方法用于解构表达式结果。
位置模式中的成员顺序必须与Deconstruct方法的参数顺序匹配。这是因为为位置模式生成的代码会调用Deconstruct方法。
结论
为了使你的代码更具表达力、更安全且更简单,请使用带有模式匹配的 switch expressions。它们支持清晰意图的功能式逻辑,在大多数现代 C# 项目中取代了传统的 switch 语句。