【C#】【模式】

73 阅读3分钟

可以使用 is 表达式、switch 语句和switch 表达式将输入表达式与任意数量的特征匹配。 C# 支持多种模式,包括声明、类型、常量、关系、属性、列表、var 和弃元。 可以使用布尔逻辑关键字 andor 和 not 组合模式。- 存在从表达式结果的运行时类型到类型 T 的装箱 或取消装箱转换。

  • 声明模式:用于检查表达式的运行时类型,如果匹配成功,则将表达式结果分配给声明的变量。
  • 类型模式:用于检查表达式的运行时类型。
  • 常量模式:用于测试表达式结果是否等于指定常量。
  • 关系模式:用于将表达式结果与指定常量进行比较。
  • 逻辑模式:用于测试表达式是否与模式的逻辑组合匹配。
  • 属性模式:用于测试表达式的属性或字段是否与嵌套模式匹配。
  • 位置模式:用于解构表达式结果并测试结果值是否与嵌套模式匹配。
  • var 模式:用于匹配任何表达式并将其结果分配给声明的变量。
  • 弃元模式:用于匹配任何表达式。
  • 列表模式:测试序列元素是否与相应的嵌套模式匹配。 在 C# 11 中引入

关系模式

请使用关系模式将表达式结果与常量进行比较

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",
};

弃元模式

可使用弃元模式 _ 来匹配任何表达式,包括 null,可以看关系模式中的例子。

列表模式

从 C# 11 开始,可以将数组或列表与模式的序列进行匹配:

int[] numbers = { 1, 2, 3 };

Console.WriteLine(numbers is [1, 2, 3]);  // True
Console.WriteLine(numbers is [1, 2, 4]);  // False
Console.WriteLine(numbers is [1, 2, 3, 4]);  // False
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]);  // True

位置模式

可使用位置模式来解构表达式结果并将结果值与相应的嵌套模式匹配

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",
};

属性模式

可以使用属性模式将表达式的属性或字段与嵌套模式进行匹配:

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."),
};

逻辑模式 (关系模式同理)

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}."),
};

常量模式

可使用常量模式来测试表达式结果是否等于指定的常量:

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)),
};

声明和类型模式

使用声明和类型模式检查表达式的运行时类型是否与给定类型兼容。 借助声明模式,还可声明新的局部变量。 当声明模式与表达式匹配时,将为该变量分配转换后的表达式结果。

int? xNullable = 7;
int y = 23;
object yBoxed = y;
if (xNullable is int a && yBoxed is int b)
{
    Console.WriteLine(a + b);  // output: 30
}