C# 7.0 新特性:模式匹配 ( pattern matching )

在 C# 中,is 是一个关键字,可以用来检查某个数据的类型是否为特定类型。这是一个表达式,返回类型为 boolean。

例如,我们可以检查某个实例是否为 Persion 类型

if (obj is Person) {
// Do something if obj is a Person.
}

在下面情况下,返回 true:

  • 表达式的类型与 is 类型相符
  • 表达式的类型为 is 类型的派生类型
  • 表达式具有一个编译时类型, 它是 is 类型的基类,在运行时的值为 is 类型的派生类型
  • 表达式实现了 is 类型的接口

支持模式匹配的 is

类型模式

在 C# 7.0 中,is 在原来的基础上,额外提供了类型转换的支持。可以在类型检查的基础上,直接支持类型转换。

在下面的示例中,我们希望检查对象的类型,如果为指定类型,我们要转型为特定的类型进行操作。

using System;

public class Example
{
public static void Main()
{
Object o = new Person("Jane");
ShowValue(o); o = new Dog("Alaskan Malamute");
ShowValue(o);
} public static void ShowValue(object o)
{
if (o is Person p) {
Console.WriteLine(p.Name);
}
else if (o is Dog d) {
Console.WriteLine(d.Breed);
}
}
} public struct Person
{
public string Name { get; set; } public Person(string name) : this()
{
Name = name;
}
} public struct Dog
{
public string Breed { get; set; } public Dog(string breedName) : this()
{
Breed = breedName;
}
}
// The example displays the following output:
// Jane
// Alaskan Malamute

等价的以前代码为:

if (o is Person) {
Person p = (Person) o;
Console.WriteLine(p.Name);
}
else if (o is Dog) {
Dog d = (Dog) o;
Console.WriteLine(d.Breed);
}

常量匹配

is 后面还可以是常量,is 测试表达式的值是否为特定常量。在以前版本中,这需要使用 switch 来支持。

using System;

public class Dice
{
Random rnd = new Random();
public Dice()
{ }
public int Roll()
{
return rnd.Next(1, 7);
}
} class Program
{
static void Main(string[] args)
{
var d1 = new Dice();
ShowValue(d1);
} private static void ShowValue(object o)
{
const int HIGH_ROLL = 6; if (o is Dice d && d.Roll() is HIGH_ROLL)
Console.WriteLine($"The value is {HIGH_ROLL}!");
else
Console.WriteLine($"The dice roll is not a {HIGH_ROLL}!");
}
}
// The example displays output like the following:
// The value is 6!

var 匹配

如果 is 后面是 var,则永远为 true 。并把值赋予后面的变量。

例如,下面代码将 item 赋予了 obj。

if (item is var obj)

需要注意的是,即使被测试的值为 null,is 表达式还是为 true。此时,变量将被赋予 null。

支持模式匹配的 Switch

所有的 c# 版本都支持常量模式,在 C#  7.0 中,现在支持类型模式了。也就是说,在 case 后面还可以是一个用来检测的类型。

case type varname

相当于在这里使用了 is 。

从 C# 7.0 开始,您还可以在上面的表达式后面附加一个返回 boolean 的 when 条件,以进一步检查。使用它的常见场景就是当值为 null 时。

using System;

public abstract class Shape
{
public abstract double Area { get; }
public abstract double Circumference { get; }
} public class Rectangle : Shape
{
public Rectangle(double length, double width)
{
Length = length;
Width = width;
} public double Length { get; set; }
public double Width { get; set; } public override double Area
{
get { return Math.Round(Length * Width,2); }
} public override double Circumference
{
get { return (Length + Width) * 2; }
}
} public class Square : Rectangle
{
public Square(double side) : base(side, side)
{
Side = side;
} public double Side { get; set; }
} public class Circle : Shape
{
public Circle(double radius)
{
Radius = radius;
} public double Radius { get; set; } public override double Circumference
{
get { return 2 * Math.PI * Radius; }
} public override double Area
{
get { return Math.PI * Math.Pow(Radius, 2); }
}
} public class Example
{
public static void Main()
{
Shape sh = null;
Shape[] shapes = { new Square(10), new Rectangle(5, 7),
sh, new Square(0), new Rectangle(8, 8),
new Circle(3) };
foreach (var shape in shapes)
ShowShapeInfo(shape);
} private static void ShowShapeInfo(Shape sh)
{
switch (sh)
{
// Note that this code never evaluates to true.
case Shape shape when shape == null:
Console.WriteLine($"An uninitialized shape (shape == null)");
break;
case null:
Console.WriteLine($"An uninitialized shape");
break;
case Shape shape when sh.Area == 0:
Console.WriteLine($"The shape: {sh.GetType().Name} with no dimensions");
break;
case Square sq when sh.Area > 0:
Console.WriteLine("Information about square:");
Console.WriteLine($" Length of a side: {sq.Side}");
Console.WriteLine($" Area: {sq.Area}");
break;
case Rectangle r when r.Length == r.Width && r.Area > 0:
Console.WriteLine("Information about square rectangle:");
Console.WriteLine($" Length of a side: {r.Length}");
Console.WriteLine($" Area: {r.Area}");
break;
case Rectangle r when sh.Area > 0:
Console.WriteLine("Information about rectangle:");
Console.WriteLine($" Dimensions: {r.Length} x {r.Width}");
Console.WriteLine($" Area: {r.Area}");
break;
case Shape shape when sh != null:
Console.WriteLine($"A {sh.GetType().Name} shape");
break;
default:
Console.WriteLine($"The {nameof(sh)} variable does not represent a Shape.");
break;
}
}
}
// The example displays the following output:
// Information about square:
// Length of a side: 10
// Area: 100
// Information about rectangle:
// Dimensions: 5 x 7
// Area: 35
// An uninitialized shape
// The shape: Square with no dimensions
// Information about square rectangle:
// Length of a side: 8
// Area: 64
// A Circle shape

其它资源:

C# 7.0 新特性:模式匹配 ( pattern matching)的更多相关文章

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

    阅读本文大概需要 2 分钟. 记得在 MS Build 2020 大会上,C# 语言开发项目经理 Mads Torgersen 宣称 C# 9.0 将会随着 .NET 5 在今年 11 月份正式发布. ...

  2. C# 7.0 新特性3: 模式匹配

    本文参考Roslyn项目Issue:#206,及Docs:#patterns. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# ...

  3. C#6.0,C#7.0新特性

    C#6.0新特性 Auto-Property enhancements(自动属性增强) Read-only auto-properties (真正的只读属性) Auto-Property Initia ...

  4. 背水一战 Windows 10 (43) - C# 7.0 新特性

    [源码下载] 背水一战 Windows 10 (43) - C# 7.0 新特性 作者:webabcd 介绍背水一战 Windows 10 之 C# 7.0 新特性 介绍 C# 7.0 的新特性 示例 ...

  5. [翻译] C# 8.0 新特性 Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南) 【由浅至深】redis 实现发布订阅的几种方式 .NET Core开发者的福音之玩转Redis的又一傻瓜式神器推荐

    [翻译] C# 8.0 新特性 2018-11-13 17:04 by Rwing, 1179 阅读, 24 评论, 收藏, 编辑 原文: Building C# 8.0[译注:原文主标题如此,但内容 ...

  6. C# 9.0新特性

    CandidateFeaturesForCSharp9 看到标题,是不是认为我把标题写错了?是的,C# 8.0还未正式发布,在官网它的最新版本还是Preview 5,通往C#9的漫长道路却已经开始.前 ...

  7. C# 7.0 新特性2: 本地方法

    本文参考Roslyn项目中的Issue:#259. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...

  8. C# 7.0 新特性1: 基于Tuple的“多”返回值方法

    本文基于Roslyn项目中的Issue:#347 展开讨论. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: ...

  9. C# 7.0 新特性4: 返回引用

    本文参考Roslyn项目中的Issue:#118. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...

  10. ASP.NET Web API 2.0新特性:Attribute Routing1

    ASP.NET Web API 2.0新特性:Attribute Routing[上篇] 对于一个针对ASP.NET Web API的调用请求来说,请求的URL和对应的HTTP方法的组合最终决定了目标 ...

随机推荐

  1. Windows安装Powershell7.x

    事件起因: 由于需要运行一个脚本,但是该脚本是广大网友群众使用Powershell7写的,我自带的是Powershell5,运行过程中总是出现莫名其妙的问题,于是决定将Powershell升级到Pow ...

  2. 【赵渝强老师】MySQL高可用架构:MHA

    MHA(Master HA)是一款开源的 MySQL 的高可用程序,它为 MySQL 主从复制架构提供了 automating master failover 功能.MHA 在监控到 master 节 ...

  3. 【赵渝强老师】如何分析Java的内存溢出问题

    一.什么是内存溢出? 内存溢出(OOM:out of memory)通俗理解就是内存不够,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出. 在J ...

  4. find_sys_call_table和kallsysms_lookup_name的区别

    find_sys_call_table 和 kallsyms_lookup_name 都可以用于查找内核符号,但它们的具体作用和使用场景有所不同.以下是两者的详细对比: 1. find_sys_cal ...

  5. 多款国产操作系统安装数据库干货文档汇总(含Oracle/MySQL/国产数据库等)

    随着国产化的逐步推进,越来越多的企业选择将数据库安装在国产操作系统上.为帮助大家了解国产操作系统上的数据库成功搭建案例与搭建方式,本文整理了墨天轮数据技术社区上用户分享的实操文档,涵盖银河麒麟.中标麒 ...

  6. efcode相关操作

    1. 下载 tool dotnet tool install -g dotnet-ef 2. 第一次迁移日志 dotnet ef migrations add init1 3. 更新数据库 datne ...

  7. Termux 使用笔记

    第一次安装完成后 发现这里面啥都没有 所以 更新源 apt update 也做不到 这是因为 源是国外 由于有墙 所以连接不上 下面这个命令可以 切换更新源 termux-change-repo 切换 ...

  8. python-requests模拟上传文件-带参数

    方法1: 1.安装requests_toolbelt依赖库 #代码实现def upload(self): login_token = self.token.loadTokenList() for to ...

  9. WebElement的常用属性和方法

    WebElement是WebDriver.find_element()方法返回的一个对象,该对象用来描述Web上的一个元素,比如输入框,按钮等.本节介绍WebElement的常用属性和方法. 一.We ...

  10. 2024御网线上Pwn方向题解

    ASM Checksec检查保护 基本上保护都关闭了 64位ida逆向 程序只有一段,并且返回地址就是输入的数据,看起来就是srop了,找一下可以用的gadget 通过异或清空rax值,然后通过异或e ...