【问题标题】:Pattern match variable scope模式匹配变量范围
【发布时间】:2016-11-18 15:31:21
【问题描述】:

Roslyn Pattern Matching spec 中声明:

模式变量的作用域如下:

如果模式出现在 if 语句的条件中,它的范围 是 if 语句的条件和受控语句,但不是 它的 else 子句。

但是最新的微软“新功能”postspresentations 显示了这个例子:

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 变量。

这是疏忽,还是规范的范围已更改?

【问题讨论】:

  • 那将是 if 语句的受控语句
  • @juharr,受控语句不只会返回吗?
  • 是的,我错过了。我实际上认为这可能指的是更高范围的i,但很难说,因为它是 beta 功能的代码 sn-p。我想你可以得到预览并测试一下。
  • 从您链接的文档中 - 模式引入的变量 - 类似于前面描述的 out 变量,因为它们可以在表达式中间声明,并且可以在最近的周围范围内使用。 这表明这与在 out 中声明变量的新功能类似。据我所知,这个例子在某种程度上几乎与 tryparse 相同
  • @AlfieGoodacre 我在新增功能中看到了这一行,但它似乎与规范文档相矛盾。

标签: c# pattern-matching c#-7.0


【解决方案1】:

来自相同的文档:

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

所以实际上这段代码:

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”的局部变量已在此范围内定义

【讨论】:

  • 感谢您通过预览检查代码!这似乎与规范文档相矛盾,我将在 github 上搜索有关更改的任何提及。我个人不喜欢这个范围,因为它与大多数其他定义变量的语法不匹配(catch & using)。
  • 嗯,是的,你是对的。这很尴尬。我希望他们能解决它。也许这只是一个错误,也许两者都在进行中。
【解决方案2】:

我在 Roslyn 问题上发布了a similar questionDavidArno 给出了答案:

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

TL;DR 认为变化不直观且 与以前范围的工作方式相矛盾。球队悲催 不用在意,变化会一直存在。

似乎已决定适用此范围,因此规范现在已过时,遗憾的是,此范围仍然存在:

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

这里的嵌入语句是指用作 另一个语句中的嵌套语句 - 块内除外。因此 if 语句的分支、while、foreach 等的主体。 都将被视为嵌入式。

结果是变量总是会逃避 一个 if,但绝不是它的分支。就好像你把卷曲放在所有的 你“应该”去的地方。

结论

虽然有点微妙,但我们将采用选项 3。它很好 余额:

它支持关键场景,包括非 Try 方法的输出变量,如 以及保镖 if 语句中的模式和输出变量。它没有 导致令人震惊和违反直觉的多层次“溢出”。它 确实意味着您将在范围内获得比当前更多的变量 限制性制度。这似乎并不危险,因为确定 分配分析将防止未初始化的使用。然而,它 防止变量名称被重用,并导致更多名称 显示在完成列表中。这似乎是一个合理的权衡。

【讨论】:

  • 我一点也不喜欢这个。 :( 这种方式更令人困惑。
  • 该死!我一直在使用is 子句来限制很多地方的范围。例如我的许多Main 方法都以类似于if (args.FirstOrDefault() is string dir) Directory.SetCurrentDirectory(dir); 的内容开头,我认为它使dir 保持整洁。不像我想象的那么整洁。
猜你喜欢
  • 2019-02-26
  • 1970-01-01
  • 1970-01-01
  • 2022-10-17
  • 2012-12-27
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多