C# Switch Expressions 怎么用?C# 开关表达式语法和用法详解?

文章导读
Previous Quiz Next 在 C# 中,switch expressions 是 pattern matching 的一种形式,它允许我们根据表达式中第一个匹配的 pattern 执行操作。C# 中的 switch expression 是 传统 switch
📋 目录
  1. 传统 Switch Statement 与 Switch Expression
  2. 使用 Switch Expression 的优势
  3. Switch Expression 的声明
  4. Switch 表达式中的模式匹配
  5. 结论
A A

C# - Switch Expressions (Pattern Matching)



Previous
Quiz
Next

在 C# 中,switch expressionspattern 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 语法。
  • 它消除了重复的 breakreturn 关键字。

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# 常量模式

常量模式 是一种更简单的方式,用于将值与固定常量进行比较。它类似于使用 "==" 操作符检查表达式是否等于特定常量值。

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

  • integerfloating-point 数值字面量
  • 一个 char
  • 一个 string 字面量。
  • 布尔值 truefalse
  • 一个 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 表达式中使用 andornot 组合多个条件。它使你的模式匹配更灵活和富有表现力。

我们使用逻辑模式组合多个条件,而无需编写嵌套的 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 语句。