模式匹配变量范围

在Roslyn模式匹配规范中,它指出:

模式变量的范围如下:

如果模式出现在if语句的条件中,则其作用域是if语句的条件和受控语句,而不是其else子句。

然而,最新的Microsoft“What’s new” post和演示文稿显示了这个例子:

public void PrintStars(object o) { if (o is null) return; // constant pattern "null" if (!(o is int i)) return; // type pattern "int i" WriteLine(new string('*', i)); } 

其中显示模式匹配i变量在模式匹配的if级别范围之外使用。

这是一个疏忽,还是从规范中改变了范围?

我在罗斯林问题上发了一个类似的问题 ,得到了DavidArno的回答:

这很长,但你可以阅读语言设计团队为什么选择以#12939这种方式“增强”语言的所有血腥细节。

TL; DR你并不是唯一一个认为变化不直观且与范围之前的工作方式相矛盾的人。 遗憾的是,这个团队并不关心,而且这种变化仍然存在。

似乎做出了这个范围适用的决定,所以规范现在已经过时了,这个范围很遗憾:

选项3:表达式变量按块,for,foreach和using语句以及所有嵌入语句确定范围:

这里的嵌入语句的含义是在另一个语句中用作嵌套语句的语句 – 除了块内部。 因此,if语句的分支,while,foreach等的主体都将被视为嵌入式。

结果是变量总是会逃避if的条件,但永远不会逃脱它的分支。 这就好像你把curlies放在你应该“应该”的所有地方。

结论

虽然有点微妙,但我们将采用选项3.它取得了良好的平衡:

它支持关键场景,包括非Try方法的vars,以及bouncer if-statements中的模式和out vars。 它不会导致恶劣和反直觉的多级“溢出”。 它确实意味着你将获得比当前限制性制度更多的变量范围。 这似乎并不危险,因为明确的分配分析会阻止未初始化的使用。 但是,它会阻止变量名重用,并导致在完成列表中显示更多名称。 这似乎是一个合理的权衡。

从相同的文档:

模式引入的变量 – 类似于前面描述的输出变量

实际上这段代码:

 if (!(o is int i)) return; // type pattern "int i" 

或多或少等于:

 int i; if (!(SomeParsingOn(o, out i))) return; // type pattern "int i" 

这意味着i被声明与if在同一级别上,这意味着它不仅适用于if ,还适用于以下语句。 当你复制if时,这是真的可以是seens:

 if (!(o is int i)) return; // type pattern "int i" if (!(o is int i)) return; // type pattern "int i" 

给出错误CS0128:已在此范围中定义名为“i”的局部变量