空值和赋值的模式匹配测试



阅读文档时,我不是 100% 清楚在检查可空性时模式匹配和赋值的含义

考虑:

#nullable enable
record EmployeeData(string Name, int Age);
bool F(string employeeName) {
EmployeeData? employee = repository.Get(employeeName); // return null if not found
if (employee is null) return false;
// do something with employee it is not null
return true;
}

这可以正确写成:

bool F(string employeeName) {
if (repository.Get(employeeName) is not EmployeeData employee) return false;
// do something with employee it is not null
return true;
}

注意:我想做:

if (repository.Get(employeeName) as EmployeeData employee is null) return false;

这更清楚,但这并不能编译:(还是有更好的方法?

让我们尝试证明employee不是空的。

我们可以从准确找出模式何时匹配开始not EmployeeData employee

not EmployeeData employee是一种not模式,其声明模式EmployeeData employee为其否定模式。根据文档,not模式

当否定模式与表达式不匹配时匹配表达式。

当表达式结果为非 null 且满足以下任一条件时,类型为T的声明模式与表达式匹配:

  • 表达式结果的运行时类型为T

  • 表达式结果的运行时类型派生自类型T[...]

  • [...]

(我省略了该列表中的其余条件,因为它们与您的问题无关)

结合这两个事实,我们可以看到,如果上述引用的否定为真,您的not EmployeeData employee将匹配,即

表达式结果为 null 或满足以下所有条件

  • 表达式结果的运行时类型不是T

  • 表达式结果的运行时类型不是从类型T[...] 派生的

  • [...]

这是您的if分支将执行的时间。

从原始代码来看,似乎repository.Get被声明为返回EmployeeData?,因此表达式结果将始终是运行时类型EmployeeData或其派生类型之一(运行时中不存在可为空的引用类型),因此上面的"以下所有条件"部分将始终为 false。剩下的就是"表达式结果为空"。

因此,我们已经证明您的if分支将在repository.Get(employeeName)null 时执行,这与原始代码相同。

如果 if 分支不执行,则它后面的代码将执行。这也意味着(通过方式)repository.Get(employeeName)不是无效的。

由于repository.Get(employeeName)的值被分配给声明的employee,如此处所述:

使用声明模式,还可以声明新的局部变量。当声明模式与表达式匹配时,将为该变量分配转换后的表达式结果 [...]

我们已经证明employee不是空的。

在 C# 8.0 中,用于使用属性模式匹配检查非空。

if(variable is { } v)   // note empty bracket {}
Console.WriteLine($"variable has value: {v}");

在线试用

裁判:

要检查字符串 s 是否为非空,您可以编写以下任何形式


if (s is object o) ... // o is of type object
if (s is string x) ... // x is of type string
if (s is {} x) ... // x is of type string
if (s is {}) ...

你为什么不试试

if (repository.Get(employeeName)  is null) return false;

最新更新