21

C# 9.0 新特性之模式匹配简化

 4 years ago
source link: http://www.cnblogs.com/willick/p/13129012.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

阅读本文大概需要 2 分钟。

记得在 MS Build 2020 大会上,C# 语言开发项目经理 Mads Torgersen 宣称 C# 9.0 将会随着 .NET 5 在今年 11 月份正式发布。目前 .NET 5 已经到了 Preview 5 阶段了,C# 9.0 也已经初具规模。忍不住激动的心情,暂停更新《C#.NET 拾遗补漏》系列几天,先要和大家分享一下我了解到的 C# 9.0 的新特性。由于新特性比较多,所以会分成几篇来讲。这是第一篇,专讲模式匹配这个特性的简化。

模式匹配(Pattern Matching)是在 C# 7.0 引入的,是对 switch 语句的增强,可以支持实现复杂的条件匹配。下面我先用一个示例来展示一下模式匹配的一般的用法。

假如现在我们要计算各种车辆在某高速的通行费,比如有下面四种车辆,分别定义为以下四个类,各个类中定义了和通行费计算相关的属性:

public class Car
{
    public int Passengers { get; set; }
}

public class DeliveryTruck
{
    public int GrossWeightClass { get; set; }
}

public class Taxi
{
    public int Fares { get; set; }
}

public class Bus
{
    public int Capacity { get; set; }
    public int Riders { get; set; }
}

下面用用模式匹配的方式来实现一个计算通行费的方法:

public decimal CalculateToll(object vehicle) =>
    vehicle switch
{
    Car { Passengers: 0}        => 2.00m + 0.50m,
    Car { Passengers: 1}        => 2.0m,
    Car { Passengers: 2}        => 2.0m - 0.50m,
    Car c                       => 2.00m - 1.0m,

    Taxi t => t.Fares switch
    {
        0 => 3.50m + 1.00m,
        1 => 3.50m,
        2 => 3.50m - 0.50m,
        _ => 3.50m - 1.00m
    },

    Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
    Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
    Bus b => 5.00m,

    DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
    DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
    DeliveryTruck _ => 10.00m,

    { } => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
    null => throw new ArgumentNullException(nameof(vehicle))
};

代码来源于文末参考链接

如果上面代码阅读起来感觉吃力,你可以先阅读文末参考链接中的第一个链接,关于模式匹配的详细介绍。

实现这个业务逻辑,若在 C# 7.0 之前,需要用一堆的 if/else 来实现。有了模式匹配后,变得方便了很多,而且使用上很灵活,代码结构也更优美。

对我来说,模式匹配是个极好的特性!但这还不够,C# 9.0 对模式匹配的写法做了进一步的简化!

以上面代码为例,模式匹配可以分为三种:简单模式、关系模式和逻辑模式。下面分别说说 C# 9.0 对三种模式的简化。

简单模式

以上面 CalculateToll 方法示例代码为例,简单模式是这种:

vehicle switch
{
    ...
    Car c => 2.00m - 1.0m
}

我们其实可以发现,上面的变量 c 声明了却没用被使用,现在 C# 9.0 中可以把它省略了:

vehicle switch
{
    ...
    Car => 2.00m - 1.0m
}

关系模式

以上面 CalculateToll 方法示例代码为例,关系模式是通过比较(大小)关系来匹配的,对应的代码片段如下:

DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
DeliveryTruck _ => 10.00m,

现在 C# 9.0 可以简写成:

DeliveryTruck t when t.GrossWeightClass switch
{
    > 5000 => 10.00m + 5.00m,
    < 3000 => 10.00m - 2.00m,
    _ => 10.00m,
}

逻辑模式

在 C# 9.0 中,你可以通过逻辑操作符 andornot 对模式进行组合,下面是一些示例:

DeliveryTruck t when t.GrossWeightClass switch
{
    < 3000 => 10.00m - 2.00m,
    >= 3000 and <= 5000 => 10.00m,
    > 5000 => 10.00m + 5.00m,
}

not null => throw new ArgumentException($"Not a known vehicle type: {vehicle}", nameof(vehicle)),
null => throw new ArgumentNullException(nameof(vehicle))

另外, not 关键字还可以用来替代 if 条件判断中的逻辑非(!),比如:

// 原来的写法
if (!(e is Customer)) { ... }

// 新的写法(易读性更好)
if (e is not Customer) { ... }

C# 9.0 还有很多其它好用的新特性,下一篇文章继续与你分享。文章写短一点不是因为我偷懒哈,而是为了促使大家一次性看完,方便大家在零碎时间阅读,避免因文章太长而成为“收藏不看”系列。

敬请关注我明天下一篇关于 C# 9.0 新特性的介绍,明天不见不散。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK