【问题标题】:Pattern matching test for null and assignnull 和 assign 的模式匹配测试
【发布时间】:2022-10-22 03:22:04
【问题描述】:

阅读文档时,在检查可空性时,我对模式匹配和赋值的含义并不是 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;

这是很多更清晰,但这不能编译:(或者有更好的方法吗?

【问题讨论】:

  • “这能正确地写成……吗?”你试过了吗?如果它有效,那么它可以,对吗?或者您是否正在寻找一些官方文档,上面写着“是的,这是受支持的行为”?
  • 从知识渊博的来源寻求确认,这很好。是的,它似乎在 null 时正确返回 false 并且当我没有收到警告说员工在那之后可以为 null 时

标签: c#


【解决方案1】:

让我们尝试证明employee 不为空。

我们可以从找出模式not EmployeeData employee 匹配的确切时间开始。

not EmployeeData employee 是一个 not patterndeclaration pattern EmployeeData employee 作为它的否定模式。根据文档,not 模式

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

T 类型的声明模式在表达式结果为非空且以下任一条件为真时匹配表达式:

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

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

  • [...]

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

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

表达式结果为 null 或以下所有条件都为真:

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

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

  • [...]

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

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

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

如果 if 分支没有执行,那么后面的代码就会执行。它还暗示(通过方式)repository.Get(employeeName) 不为空。

由于repository.Get(employeeName) 的值被分配给声明的employee,正如这里所说:

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

我们已经证明employee 不为空。

【讨论】:

  • 谢谢 ! “从您的原始代码看来,repository.Get 被声明为返回 EmployeeData”,不它返回“EmployeeData?”正如我的问题的评论中所记录的那样.. 否则检查 null 是没有意义的。但我认为这并没有真正改变你的答案
  • @kofifus 你是对的。我进行了编辑以使该部分更加严格。
【解决方案2】:

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

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

try online

Ref:

块引用 要检查字符串 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 {}) ...

【讨论】:

    【解决方案3】:

    你为什么不试试

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

    【讨论】:

    • 因为那样你就不能继续“与员工做某事它不是空的”
    • 是的。如果在那个函数中他只想返回真或假,那就更好了
    猜你喜欢
    • 2016-10-07
    • 2014-10-06
    • 1970-01-01
    • 2018-03-12
    • 2015-01-10
    • 2022-01-11
    • 2017-02-08
    • 2021-10-11
    • 1970-01-01
    相关资源
    最近更新 更多