模式匹配

模式匹配性能更好,因为 C# 编译器会根据你的模式编译出最优的匹配路径。

switch 表达式

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

属性模式

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

元组模式

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

位置模式

某些类型包含 Deconstruct 方法,该方法将其属性解构为离散变量。

public class 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);
}

 

        public record Order(int Items, decimal Cost);

public decimal CalculateDiscount(Order order) =>
    order switch
    {
        ( > 10, > 1000.00m) => 0.10m,
        ( > 5, > 50.00m) => 0.05m,
        ( _, Cost: > 250.00m) => 0.02m,
        null => throw new ArgumentNullException(nameof(order), "Can't calculate discount on null order"),
        _ => 0m,
    };

 

static Quadrant GetQuadrant(Point point) => point switch
{
    (0, 0) => Quadrant.Origin,
    var (x, y) when x > 0 && y > 0 => Quadrant.One,
    var (x, y) when x < 0 && y > 0 => Quadrant.Two,
    var (x, y) when x < 0 && y < 0 => Quadrant.Three,
    var (x, y) when x > 0 && y < 0 => Quadrant.Four,
    var (_, _) => Quadrant.OnBorder,
    _ => Quadrant.Unknown
};

 

列表模式

 列表模式提供了一种将模式应用于序列的任何元素的方法。 此外,还可以应用 放弃模式 (_) 来匹配任何元素,或者应用 切片模式 来匹配零个或多个元素。 

public void MatchElements(int[] array)
{
    if (array is [0,1])
    {
        Console.WriteLine("Binary Digits");
    }
    else if (array is [1,1,2,3,5,8, ..])
    {
        Console.WriteLine("array looks like a Fibonacci sequence");
    }
    else
    {
        Console.WriteLine("Array shape not recognized");
    }
}

 

 模式匹配支持递归模式

string QueryMessage(Entry entry)
{
    return entry switch
    {
        UserEntry u => dbContext1.User.FirstOrDefault(i => i.Id == u.UserId) switch
        {
            null => dbContext2.User.FirstOrDefault(i => i.Id == u.UserId)?.Content ?? "",
            var found => found.Content
        },
        DataEntry d => dbContext1.Data.FirstOrDefault(i => i.Id == d.DataId) switch
        {
            null => dbContext2.Data.FirstOrDefault(i => i.Id == u.DataId)?.Content ?? "",
            var found => found.Content
        },
        EventEntry { EventId: var eventId, CanRead: true } => dbContext1.Event.FirstOrDefault(i => i.Id == eventId) switch
        {
            null => dbContext2.Event.FirstOrDefault(i => i.Id == eventId)?.Content ?? "",
            var found => found.Content
        },
        EventEntry { CanRead: false } => "",
        _ => throw new InvalidArgumentException("无效的参数")
    };
}

 

C# 9 包括新的模式匹配改进:

  • 类型模式 与对象匹配特定类型
  • 带圆括号的模式强制或强调模式组合的优先级
  • 联合 and 模式要求两个模式都匹配
  • 析取 or 模式要求任一模式匹配
  • 否定 not 模式要求模式不匹配
  • 关系模式要求输入小于、大于、小于等于或大于等于给定常数。
public static bool IsLetter(this char c) =>
    c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';

用于 NULL 检查的新语法:e is not null

 

string WaterState(int tempInFahrenheit) =>
    tempInFahrenheit switch
    {
        (> 32) and (< 212) => "liquid",
        < 32 => "solid",
        > 212 => "gas",
        32 => "solid/liquid transition",
        212 => "liquid / gas transition",
    };

 

嵌套属性模式匹配改进

以前在匹配嵌套属性的时候需要这么写:

if (a is { X: { Y: { Z: 4 } } }) { ... }

现在只需要简单的:

if (a is { X.Y.Z: 4 }) { ... }

就可以了。

posted @ 2020-08-06 19:21  yetsen  阅读(212)  评论(0编辑  收藏  举报