短路 If 条件不起作用

Short-Circuit If Condition Does not work

我有一个抛出 NullReferenceException 的代码段。代码段是这样的

if (string.IsNullOrWhiteSpace(user.FirstName) && !(user.FirstName.Length <= 64))
{
    // Some Code
}

这里的 if 条件首先应该检查 user.FirstName 是 Null 还是 WhiteSpace。当 user.FirstName 的值为 null 时,此代码段抛出 NullReferenceException。我假设这是通过检查 user.FirstNameLength 抛出的,但由于这是短路检查,第一个表达式不应该满足条件并执行 if 块内的代码。或者我在这里遗漏了什么。

第二部分只在

时执行
string.IsNullOrWhiteSpace(user.FirstName)

结果为真。所以你需要

!string.IsNullOrWhiteSpace(user.FirstName) && !(user.FirstName.Length <= 64)

string.IsNullOrWhiteSpace(user.FirstName) || !(user.FirstName.Length <= 64)

取决于您的要求。此外,user 可能是 null,在这种情况下,短路根本无济于事。

&&并没有像你想象的那样短路,恰恰相反。

如果第一个条件为真,它需要检查两个条件,只有当两个条件都为真时,它才会执行内部块:如果第一个条件为真(即 user.FirstName 为空),则它也需要检查第二个是否为真,因此您的异常(因为 user.FirstName 在检查其 Length 时将始终为空 - 除非它为空或空白)。

编辑:由于上面这段话对某些人来说似乎不清楚:我不是说&&不短路(它会如果第一个条件是 false,则短路),我是说它不会像 OP

预期的那样短路

在发布断言之前让我们分析一下你的问题 (C# 解决方案包含 十亿行代码 :您真的认为 if这么普通的构造能行不通吗?)

您似乎想检查用户名是否无效一个:

  1. 如果用户名为 null 或空或白色 space
  2. 或者如果它太长(超过 64 个字符)

现在实现很清楚了:

  const int USER_NAME_MAX_LENGTH = 64;

  if (string.IsNullOrWhiteSpace(user.FirstName) || 
      user.FirstName.Length > USER_NAME_MAX_LENGTH) {
    // user name is invalid
    ...   
  }

在您的示例中,NullReferenceException 可能有两个不同的原因:

- Value `user` is null;
- `user.FirstName` is null.

我假设您已经检查过 user 是否不为空,所以让我们跳过那个。

现在假设 user.FirstName 为空,那么会发生什么?

第一个条件 string.IsNullOrWhiteSpace(user.FirstName) 将导致 true。这足以让 if 语句执行内部代码块还是应该评估第二个条件?

来看看这个真相-table:

A  && B     = RESULT
--------------------
False False = False
False True  = False
True  False = False
True  True  = True

因此,当使用 && 运算符时,只有当两个子条件都为真时,总条件才为真。所以当第一个条件为真时,第二个条件仍然需要评估。根据 C# 的 truth-table 的简单翻译是(其中 ??? 代表:不关心):

A  && B     = RESULT
--------------------
False ???   = False
True  False = False
True  True  = True

所以当检查你的第二个条件时,属性 user.FirstName.Length 被读取,导致你的 NullReferenceException.

如何防止这种情况。正如其他人所说,您可能希望在以下情况下执行代码块: FirstName 为 NULL OR Empty OR WhiteSpace OR 大于 64。基本上,您当前的条件检查 FirstName 是否为 NULL AND 是否大于 64.

所以...使用 ||-运算符:

if (string.IsNullOrWhiteSpace(user.FirstName) || !(user.FirstName.Length <= 64))

或更清楚:

if (string.IsNullOrWhiteSpace(user.FirstName) || (user.FirstName.Length > 64))

C# 真相-table 将是:

A  || B     = RESULT
--------------------
False False = False
False True  = True
True  ???   = True

你可以清楚地看到"short circuit"部分。