为什么 intellicode '... 不是 null' 当它是 cleary null 时?

Why does intellicode '... is not null' when it is cleary null?

编辑:

感谢 canton7,我将研究 nullable reference types 因为这是此处显示的 C# 8 功能。

编辑2:

TL;DR:消息“‘_products’在此处不为空。” 纯粹 基于变量 _products 定义。如果它被定义为可空引用类型,它会说“这里可能为空”,如果它被定义为非可空引用类型(=正常,没有'?'的基本定义)它会说,什么显示在下面的图片。这两种情况都只是hints/warnings,不会改变编译后的代码。

原问题:

调用方式:

protected override async Task OnInitializedAsync() //ignore the Polymorphism
{
    _products = await ProdService.GetProductListAsync();
    Console.WriteLine("_products: " + _products + " | is null?: " + (_products == null));
//output: <<_products:   is null? True>>
}

图片:

调用方法:

public async Task<List<Product>> GetProductListAsync()
{
    return null;
}

图片:

您启用了 C# 8 功能“可空引用类型”(NRT)。这增加了一层静态分析,它会告诉您引用类型何时可能为 null,并在您取消引用可能为 null 的内容时发出警告。参见 this doc and this MSDN blog post

您可以通过在 .csproj 中设置 <Nullable>disable</Nullable> 来禁用 NRT。

签名 Task<List<Product>> GetProductListAsync() 承诺此方法将 return 一个 non-null Task,包含一个 non-null List of non-null Products.

任何调用此方法的代码只能看到签名。编译器相信您正确编写了签名。由于签名表明此方法不会 return null,这意味着 _products 显示为“not null”。

(想想如果这个方法定义在不同的DLL中会发生什么。编译器没有可用的源代码来分析它。这种whole-program类型推断也非常昂贵并且脆弱:让程序员明确声明而不是推断接口要好得多。)

但是,您在方法的实现中违背了这一承诺,其中您 return null。 是编译器对你抱怨的地方。最终屏幕截图中的 CS8603 显示编译器抱怨,因为方法签名承诺您不会 return null,但您有 return null.

如果方法真的可以return null,那么它的签名应该是:

Task<List<Product>?> GetProductListAsync()

这将使 return null 上的警告消失,_products 将显示为“可能为空”。