为什么 `foo is not { } bar` 在语义上不等同于 `!(foo is { } bar)`?

问题描述

让我们在 C# 中使用 string foo 变量。

为什么以下语句在语义上不等价?

if (!(foo is { } bar) || bar.Length == 0)

if (foo is not { } bar || bar.Length == 0)

对于 foo = null,两者的行为似乎相同。

var foo = null;

if (!(foo is { } bar) || bar.Length == 0)
{
    Console.WriteLine("bar");
}
  
if (foo is not { } baz || baz.Length == 0)
{
    Console.WriteLine("baz");
}

但是对于 foo = "something",第一个语句有效,但第二个语句失败并显示 NullReferenceException

检查sharplab

这是一个功能吗?

编辑:似乎是一个错误https://github.com/dotnet/roslyn/issues/51996#issuecomment-803508111

解决方法

来自对问题的评论:

您是否会遇到 definite assignment 的问题? Per the docs,只有当 is 模式为真时,模式变量才被认为是明确分配的。 The changelog 链接到许多关于该主题的 git 问题。

来自文档的更多见解:

如果我们选择将此类工作推迟到以后(我建议这样做),我们可以说在 C# 9 中的 notor 下,可能不会声明模式变量。然后,我们将有时间积累一些经验,以便深入了解以后放松的可能价值。