11.1 常规
模式是一种语法形式,可与运算符(is
)和switch_statement(§13.8.3)一起使用,以表达要对其比较传入数据的数据的形状。 针对 switch 语句的表达式或运算符左侧的relational_expression(每个运算符称为is
)测试模式。
11.2 模式窗体
11.2.1 常规
模式可能具有以下形式之一:
pattern
: declaration_pattern
| constant_pattern
| var_pattern
;
declaration_pattern和var_pattern可能会导致局部变量的声明。
每个模式窗体定义可应用于该模式的输入值的类型集。 如果P
模式是模式可能匹配的类型之一,则模式T
T
类型。 如果某个模式出现在程序中以匹配类型的P
模式输入值(§11.1T
如果P
不适用T
)。
示例:以下示例生成编译时错误,因为编译时类型
v
为TextReader
. 类型的TextReader
变量永远不能具有与以下项兼容的string
值:TextReader v = Console.In; // compile-time type of 'v' is 'TextReader' if (v is string) // compile-time error { // code assuming v is a string }
但是,由于编译时类型
v
为object
,因此以下代码不会生成编译时错误。 类型的object
变量可以具有与引用兼容的string
值:object v = Console.In; if (v is string s) { // code assuming v is a string }
end 示例
每个模式窗体定义模式 在运行时匹配 值的一组值。
11.2.2 声明模式
declaration_pattern用于测试某个值是否具有给定类型,如果测试成功,请在该类型的变量中提供该值。
declaration_pattern
: type simple_designation
;
simple_designation
: single_variable_designation
;
single_variable_designation
: identifier
;
值的运行时类型使用 is-type 运算符中指定的相同规则(§12.12.12.12.1)针对模式中的类型进行测试。 如果测试成功,则模式 与该值匹配 。 如果 类型 为可以为 null 的值类型(§8.3.12),则为编译时错误。 此模式形式永远不会与值 null
匹配。
注意:is-type 表达式
e is T
和声明模式e is T _
在不是可以为 null 的类型时T
是等效的。 尾注
给定模式输入值(§11.1)e,如果simple_designation是_
,则表示放弃(§9.2.9.2)和 e 的值不绑定到任何内容。 (虽然具有该名称 _
的声明变量可能位于该点的作用域内,但在此上下文中看不到该命名变量。如果 simple_designation 是任何其他标识符,则会引入由给定标识符命名的给定类型的局部变量(§9.2.9.1)。 当模式与值匹配时,向该局部变量分配模式输入值的值。
模式输入值和给定类型的静态类型的某些组合被视为不兼容,并导致编译时错误。 如果存在标识转换、隐式或显式引用转换、装箱转换或从中取消装箱转换或E
打开类型(§8.4.3),则表示E
T
声明模式命名类型T
适用于与该类型兼容的每种类型E
。E
T
注意:在检查可能为结构或类类型的类型时,对开放类型的支持最有用,并且要避免装箱。 尾注
示例:声明模式可用于执行引用类型的运行时类型测试,并替换成语
var v = expr as Type; if (v != null) { /* code using v */ }
稍微简洁一点
if (expr is Type v) { /* code using v */ }
end 示例
如果 类型 为可为 null 的值类型,则为错误。
示例:声明模式可用于测试可为 null 类型的值:如果值不为 null 且
Nullable<T>
T
为或某些基类型或接口T2 id
,则T2
类型(或装箱T
)的值与类型模式T
匹配。 例如,在代码片段中int? x = 3; if (x is int v) { /* code using v */ }
语句的条件
if
在true
运行时,变量v
保存块内类型的3
值int
。 end 示例
11.2.3 常量模式
constant_pattern用于针对给定常量值测试模式输入值(§11.1)的值。
constant_pattern
: constant_expression
;
如果存在从常量表达式P
到该类型的隐式转换,则常量模式P
类型T
。
对于常量模式 P
,其 转换的值 为
- 如果模式输入值的类型是整型类型或枚举类型,则模式的常量值转换为该类型;否则
- 如果模式输入值的类型是整型类型或枚举类型的可为 null 版本,则模式的常量值转换为其基础类型;否则
- 模式常量值的值。
给定模式输入值 e 和具有转换值 v 的常量模式P
,
- 如果 e 具有整型类型或枚举类型,或其中一种可为 null 的形式,并且 v 具有整型类型,则模式
true
;否则 - 如果返回,则模式
P
object.Equals(e, v)
。true
示例:
switch
以下方法中的语句在其事例标签中使用五个常量模式。static decimal GetGroupTicketPrice(int visitorCount) { switch (visitorCount) { case 1: return 12.0m; case 2: return 20.0m; case 3: return 27.0m; case 4: return 32.0m; case 0: return 0.0m; default: throw new ArgumentException(...); } }
end 示例
11.2.4 Var 模式
var_pattern 匹配每个值。 也就是说,具有 var_pattern 的模式匹配操作始终成功。
var_pattern适用于每种类型。
var_pattern
: 'var' designation
;
designation
: simple_designation
;
给定模式输入值(§11.1)e,如果指定为_
,则表示放弃(§9.2.9.2),e 的值不绑定到任何内容。 (尽管具有该名称的声明变量可能位于该点的范围中,但在此上下文中看不到该命名变量。如果指定为任何其他标识符,则 e 的值将绑定到该名称的新引入局部变量(§9.2.9.1),其类型为 e 的静态类型,并将模式输入值分配给该局部变量。
如果名称var
绑定到使用var_pattern的类型,则为错误。
11.3 模式子建议
在 switch 语句中,如果事例的模式被前面的未保护事例集(§13.8.3)子化,则为错误。 非正式地说,这意味着任何输入值都将与前面的案例之一匹配。 以下规则定义一组模式何时将给定模式子化:
P
P
常量K
。
如果满足以下任一条件,则一组模式Q
会子化模式P
:
-
P
是一个常量模式,集中Q
的任何模式都与转换后的值匹配P
-
P
是 var 模式,模式集Q
对于模式输入值的类型(§11.4null
-
P
是具有类型的T
声明模式,并且该类型Q
(§11.4)的模式T
集是详尽的。
11.4 模式详尽
非正式情况下,如果对于该类型(非 null)的每个可能值,则一组模式对于类型而言都是详尽的,则集中的某些模式适用。 以下规则定义类型一组模式 何时详尽 :
如果满足以下任一条件,则一组模式Q
T
的:
-
T
是整数或枚举类型,或其中一个的可为 null 版本,对于'不可为 null 的基础类型的每个可能值T
,某些Q
模式将匹配该值;或 - 某些模式
Q
是 var 模式;或 - 某些模式
Q
是D
,并且存在标识转换、隐式引用转换或从T
中转换到D
的装箱转换。
示例:
static void M(byte b) { switch (b) { case 0: case 1: case 2: ... // handle every specific value of byte break; // error: the pattern 'byte other' is subsumed by the (exhaustive) // previous cases case byte other: break; } }
end 示例