对象模式匹配导致未初始化的变量

Object pattern matching results in uninitialized variable

查找值是否不是 null 的模式匹配是使用具有相应预期类型的​​ is 关键字完成的(如有必要,包括强制转换)。模式 !(obj is object instance) returns true 如果 obj 不是 nullfalse 如果 objnull。同时如果 obj 不是 null 它被捕获在变量 instance.

[Fact]
public void Old_pattern_matching_for_non_null_object()
{
    var obj = new object();
    if (!(obj is object instance)) // false
        return;

    if (instance is null) // false
        throw new Exception("Never reached");

    // this does not throw an exception (test passes)
}

在 C#8 中引入了一种新的编写方式,使用 { } 表示 non-null(无需转换),将代码“简化”为

[Fact]
public void Csharp_8_pattern_matching_for_non_null_object()
{
    var obj = new object();
    if (!(obj is { } instance)) // false
        return;

    if (instance is null) // false
        throw new Exception("Never reached");

    // this does not throw an exception (test passes)
}

在 C#9 中,引入了新关键字 not,旨在将 !(x is null) 等模式简化为 x is not null。如果我现在尝试将新的 not 关键字应用于包含 { } 的模式,我会得到一个非常令人惊讶的结果:

[Fact]
public void Csharp_9_pattern_matching_for_non_null_object()
{
    var obj = new object();
    if (obj is not { } instance) // false
        return;

    if (instance is null) // true
        throw new Exception("Why the heck is this null");

    // this does throw an exception (test fails)
}

即使 obj 不是 nullinstance 变量也未初始化。为了得到一个更好的,通过避免 obj 变量 instance 将被初始化:

[Fact]
public void Csharp_9_pattern_matching_for_non_null_object_without_obj_variable()
{
    if (new object() is not { } instance) // false
        return;

    if (instance is null) // false
        throw new Exception("Never reached");
        
    // this does not throw an exception (test passes)
}

有人知道这是否是我们想要的行为吗?如果是,其背后的意图是什么?

正如 Yari Halberstadt 所指出的,这实际上是一个编译器错误。我在 Csharplang discussions 上发布了一个关于此的问题,并被告知此问题已得到解决。

正如 canton7 指出的那样,该问题最近已修复,目前尚未发布。

一旦发布,所有示例测试用例都应该通过。根据 this C#9 release blog ,失败的测试用例实际上是一个有效的用例,其中使用了以下示例:

if (e is not Customer c) { throw ... } // if this branch throws or returns...
var n = c.FirstName; // ... c is definitely assigned here