模式匹配变量范围

本文关键字:范围 变量 模式匹配 | 更新日期: 2023-09-27 18:18:33

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

模式变量的作用域如下:

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

然而,最新的微软"What's new"帖子和演示文稿都展示了这个例子:

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));
}

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

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

模式匹配变量范围

来自同一文档:

(模式引入的变量)类似于前面描述的out变量

所以实际上这段代码:

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:

时,可以看出这是正确的
if (!(o is int i)) return; // type pattern "int i"
if (!(o is int i)) return; // type pattern "int i"

给出错误CS0128:名为'i'的局部变量已经在此作用域中定义。

我发布了一个类似于Roslyn问题的问题,并由DavidArno给出了答案:

它很长,但你可以阅读所有关于为什么使用这种语言的血腥细节设计团队选择以这种方式在#12939处"增强"语言。

你不是唯一一个认为这种改变不直观和不合理的人与以前scope的工作方式相矛盾。团队悲伤地说不用在意,更改就在这里。

似乎决定了这个范围将适用,所以规范现在已经过时了,而这个范围很遗憾地留在这里:

选项3:表达式变量的作用域是block, for, foreach和使用语句,以及所有嵌入语句:

这里所说的嵌入语句,是指用作语句嵌套在另一个语句中——块内除外。因此if语句的分支,while、foreach等语句体。

结果是变量总是会转义的条件是树,却不是树的枝。就好像你在所有的你应该去的地方

结论

虽然有点微妙,但我们将采用选项3。它打得很好平衡:

它支持关键场景,包括非try方法的out变量,如以及在边界if语句中的模式和out变量。它不导致严重和反直觉的多层次"溢出"。它这是否意味着你将获得比当前更多的变量严格的制度。这看起来并不危险,因为确实如此赋值分析将防止未初始化的使用。然而,它防止变量名被重用,并导致更多的名称显示在完成列表中。这似乎是一个合理的权衡。