C# 模式&模式匹配

  模式

    • is 表达式
    • switch 语句
    • switch 表达式(C# 8.0 引入)

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

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

 

  模式匹配

  • C# 7.0 - 7.3

    模式匹配支持 is 表达式和 switch 表达式。

    以下代码检查变量是否为 int,如果是,则将其添加到当前总和:

if (input is int count)
    sum += count;

    更新后的 switch 语句有几个新构造:

    • switch 表达式的控制类型不再局限于整数类型、Enum 类型、string 或与这些类型之一对应的可为 null 的类型。可能会使用任何类型。
    • 可以在每个 case 标签中测试 switch 表达式的类型。 与 is 表达式一样,可以为该类型指定一个新变量。
    • 可以添加 when 子句以进一步测试该变量的条件。
    • case 标签的顺序现在很重要。 执行匹配的第一个分支;其他将跳过。
public static int SumPositiveNumbers(IEnumerable<object> sequence)
{
    int sum = 0;
    foreach (var i in sequence)
    {
        switch (i)
        {
            case 0:
                break;
            case IEnumerable<int> childSequence:
            {
                foreach(var item in childSequence)
                    sum += (item > 0) ? item : 0;
                break;
            }
            case int n when n > 0:
                sum += n;
                break;
            case null:
                throw new NullReferenceException("Null found in sequence");
            default:
                throw new InvalidOperationException("Unrecognized type");
        }
    }
    return sum;
}
    • case 0: 是常量模式
    • case IEnumerable<int> childSequence: 是声明模式
    • case int n when n > 0: 是具有附加 when 条件的声明模式。
    • case null: 是 null 常量模式。
    • default: 是常见的默认事例。

 

  • C# 8.0

    switch 表达式

    更简洁的表达式语法

    下面以 彩虹颜色 枚举举例

public enum Rainbow
{
    Red,
    Orange,
    Yellow,
    Green,
    Blue,
    Indigo,
    Violet
}

    如果应用定义了通过 RG 和 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 事例替换为 _ 弃元。
    • 正文是表达式,不是语句。

    属性模式

    下面使用属性模式从地址和价格计算销售税:

    State 是 地址Address 的一个属性。

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

    位置模式

    暂无

 

  • C# 9.0

    模式匹配改进:

    • 类型模式要求在变量是一种类型时匹配
    • 带圆括号的模式强制或强调模式组合的优先级
    • 联合 and 模式要求两个模式都匹配
    • 析取 or 模式要求任一模式匹配
    • 否定 not 模式要求模式不匹配
    • 关系模式要求输入小于、大于、小于等于或大于等于给定常数。
public static bool IsLetter(this char c) =>
    c is >= a and <= z or >= A and <= Z;
public static bool IsLetterOrSeparator(this char c) =>
    c is (>= a and <= z) or (>= A and <= Z) or . or ,;
if (e is not null)
{
    // ...
}

     类型模式示例:

public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
    Car => 2.00m,
    Truck => 7.50m,
    null => throw new ArgumentNullException(nameof(vehicle)),
    _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};

 

  • C# 10.0(预览版)

    

C# 模式&模式匹配

上一篇:09-redis的五种数据结构


下一篇:谈谈鸿蒙操作系统