阅读文档时,我不是 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;