在第3章中,我们展示了如何使用 is 运算符验证引用的转换是否成功:
以上代码可以更加简洁地写为:
以上代码引入了一种称为类型模式的模式。除了类型模式之外, is 运算符还支持其他在C#最近几个版本中引入的模式。例如,属性模式:
模式可以在以下上下文中使用:
· is 运算符之后( variable is pattern )。
· switch语句中。
· switch表达式中。
我们在2.11.3.5和3.2.2.4节中介绍了类型模式(并简要介绍了元组模式)。本节将介绍更多C#最近版本中引入的高级模式。
大多数特定模式都是随switch语句或表达式一起使用的。这些模式可以减少 when 子句的使用,也可以在原本无法支持的场景下使用switch。
本节介绍的模式在某些场景下是有一定作用的。但请牢记这些高度模式化的switch语句都可以被简单的 if 语句——或者在某些情况下还可以使用三元运算符——来替代,而且替换后的代码量并不会显著增加。
var模式是类型模式的变体,即将类型名称替换为了 var 关键字。由于转换必定成功,因此它的目的仅仅是引入一个可以重复使用的变量:
上述代码等价于以下代码:
能够在表达式体方法中使用var模式引入一个可复用的变量(本例中为 upper )的确方便。但是该模式只能在方法返回类型为 bool 时使用。
常量模式可以直接与常量进行匹配,常用于处理 object 类型:
以上示例中的粗体文字等价于:
(C#无法直接使用 == 比较 object 与常量的值,因为运算符是静态的,编译器需要提前知道对象的类型。)
因此,这种模式仅在没有合理替代方案的情况下才有少许的用处:
常量与模式组合器共同使用可以发挥更大的作用,我们稍后将进行介绍。
C# 9支持在模式中使用 < 、 > 、 <= 和 >= 运算符:
这种模式适合与 switch 配合使用:
关系模式可以和模式组合器共同使用以发挥更大作用。
关系模式也可以和编译时类型为 object 的变量配合使用。但若和数值常量一起使用则需要特别注意。在以下示例中,最后一行将输出False,因为我们试图匹配decimal(十进制)值与整数值:
从C# 9开始,我们可以通过 and 、 or 与 not 关键字将模式组合起来:
与 && 和 || 运算符类似, and 比 or 拥有更高的优先级。我们也可以使用括号更改运算顺序。
我们可以将 not 组合器与类型模式巧妙结合,测试对象是否是特定类型:
这比下列写法要好懂得多:
元组模式(C# 8引入)用于匹配元组:
这种模式可用于switch多个值:
元组模式可以理解为位置模式(C# 8+)的一种特殊形式。位置模式可以匹配任何定义了 Deconstruct 方法(请参见3.1.5节)的类型。在以下示例中,我们利用了编译器为 Point 记录生成的解构器:
在匹配的过程中可以同时进行解构操作,使用以下语法:
以下 switch 表达式结合使用了类型模式和位置模式:
属性模式(C# 8)可以匹配对象的一个或者多个属性值。例如,在介绍 is 运算符时我们曾给出以下示例:
但是,上述代码相比以下代码并没有显著的优势:
但是将属性模式与swtich语句和表达式联合使用优势就明显了。以 System.Uri 类为例(这个类表示一个URI),这个类定义了 Scheme 、 Host 、 Port 和 IsLoopback 属性。在以下防火墙代码中,我们可以使用switch表达式配合属性模式来决定是否允许访问特定的URI:
属性模式支持属性嵌套,因此以下代码是合法的:
而上述代码在C# 10中可以进一步简化为:
还可以在属性模式中使用其他模式,包括使用关系模式:
而更详细的条件可以使用 when 子句来表示:
将属性模式和类型模式结合也是可行的:
就像类型模式那样,以上用法也可以在子句的末尾引入变量,并使用该变量的值:
该变量也可以在 when 子句中使用:
属性模式中甚至可以在属性一级引入变量:
新引入的变量可以使用隐式类型,因此我们可以将 string 替换为 var 。以下是完整的示例代码:
想要找到一个通过上述模式而令代码变得更加简洁的例子并不容易。与上述代码相比,以下两种实现方式的代码反而更短:
或者