zoukankan      html  css  js  c++  java
  • C# 9.0 新特性之模式匹配简化

    阅读本文大概需要 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 新特性的介绍,明天不见不散。

    参考:

    1. https://bit.ly/2MNc0DJ
    2. https://bit.ly/2UzEIwu
  • 相关阅读:
    终于看到费德勒在法网如愿!
    o(∩_∩)o...,今天去博客园了!
    条款4:使用Conditional特性代替#if条件编译
    MSDTC无法启动的解决方法
    2009 很有意义的一天
    从现在开始,争取记录每天所学到的、所感受到的、所遇见到的点点滴滴!
    了解MOSS2007 内容类型ID(Content Type IDs)命名规则
    CreateSpecificCulture('zhcn')和new CultureInfo('zhcn')的区别
    金华大显数码科技有限公司诚聘
    使用SQL Server中按位于来表示组合状态
  • 原文地址:https://www.cnblogs.com/willick/p/13129012.html
Copyright © 2011-2022 走看看