13

我已经看过几次类似的东西......我讨厌它。这基本上是“欺骗”语言吗?或者..你会认为这是“好的”,因为 IsNullOrEmpty 总是首先被评估?

(我们可以争论一个字符串在从函数中出来时是否应该为 NULL,但这并不是真正的问题。)

string someString;
someString = MagicFunction();

if (!string.IsNullOrEmpty(someString) && someString.Length > 3)
{
    // normal string, do whatever
}
else
{
   // On a NULL string, it drops to here, because first evaluation of IsNullOrEmpty fails
   // However, the Length function, if used by itself, would throw an exception.
}

编辑: 再次感谢大家提醒我这种语言基础。虽然我知道它“为什么”起作用,但我不敢相信我不知道/不记得这个概念的名称。

(以防有人想要任何背景。我在对由 NULL 字符串和 .Length > x 异常生成的异常进行故障排除时遇到了这个问题......在代码的不同位置。所以当我看到上面的代码时,除了其他所有内容之外,我的挫败感从那里接管了。)

4

15 回答 15

106

您正在利用一种称为短路的语言功能。这不是在欺骗语言,而是实际上完全按照设计使用的方式使用了功能。

于 2009-05-07T20:52:06.450 回答
24

如果您问是否可以依赖“短路”关系运算符&&and ||,那么是的,这完全没问题。

于 2009-05-07T20:51:20.053 回答
6

这没有任何问题,因为您只是想确保不会出现空指针异常。

我认为这样做是合理的。

使用扩展,您可以使其更清洁,但基本概念仍然有效。

于 2009-05-07T20:49:33.507 回答
5

这段代码完全有效,但我喜欢使用 Null Coalesce Operator 来避免空类型检查。

string someString = MagicFunction() ?? string.Empty;
if (someString.Length > 3)
{
    // normal string, do whatever
}
else
{
   // NULL strings will be converted to Length = 0 and will end up here.
}
于 2009-05-07T20:54:55.070 回答
4

这没有什么问题。

if(条件是从左到右评估的,所以像这样堆叠它们是完全可以的。

于 2009-05-07T20:51:08.057 回答
2

在我看来,这是有效的代码(虽然声明一个变量并在下一行分配它很烦人),但您可能应该意识到,您也可以在字符串长度为 < 的情况下输入 else 块3.

于 2009-05-07T20:52:30.723 回答
2

这是完全有效的,以这种方式使用它没有任何问题。如果您遵循该语言的记录行为,那么一切都很好。在 C# 中,您使用的语法是条件逻辑运算符,可以在MSDN上找到它们的文档

对我来说,这与在同一语句中进行乘法和加法运算时不使用括号的情况相同,因为语言记录了乘法运算将首先执行。

于 2009-05-07T20:53:12.513 回答
2

在我看来,这就像对逻辑短路的完全合理的使用——如果有的话,那就是在欺骗语言。我最近才从没有短路的 VB6 来这真的让很恼火。

需要注意的一个问题是,您可能需要在 else 子句中再次测试 Null,因为 - 正如所写的那样 - 您正在使用 Null 字符串和长度小于三个字符串。

于 2009-05-07T20:55:45.020 回答
1

在大多数情况下,依靠短路是“正确的事情”。它导致代码更简洁,活动部件更少。这通常意味着更容易维护。在 C 和 C++ 中尤其如此。

我会认真重新考虑雇用不熟悉(也不知道如何使用)短路操作的人。

于 2009-05-07T21:44:53.420 回答
0

我觉得没问题 :) 你只是确保你不访问 NULL 变量。实际上,我总是在对变量进行任何操作之前进行此类检查(另外,在索引集合等时) - 它更安全,是最佳实践,仅此而已..

于 2009-05-07T20:54:01.373 回答
0

这是有道理的,因为默认情况下 C# 会短路条件,所以我认为可以利用它来发挥自己的优势。在 VB 中,如果开发人员使用 AND 而不是 ANDALSO,可能会出现一些问题。

于 2009-05-07T20:56:19.183 回答
0

我认为这与以下内容没有什么不同:

INT* pNumber = GetAddressOfNumber();

if ((pNUmber != NULL) && (*pNumber > 0))
{
  // valid number, do whatever
}
else
{
  // On a null pointer, it drops to here, because (pNumber != NULL) fails
  // However, (*pNumber > 0), if used by itself, would throw and exception when dereferencing NULL
}

它只是利用了语言中的一个特性。我认为,自从 C 开始以这种方式执行布尔表达式(或者任何一种语言首先使用它)以来,这种习惯用法就已经很普遍了。)

于 2009-05-07T21:00:15.617 回答
0

如果它是您编译成程序集的 c 中的代码,那么不仅短路了正确的行为,而且速度更快。在机器语言中,if 语句的各个部分是一个接一个地计算的。不短路比较慢。

于 2009-05-07T21:01:09.720 回答
0

编写代码对公司来说要花费很多美元。但是维护成本更高!

所以,我同意你的观点:很可能这行代码不会被必须在 2 年内阅读并更正它的人立即理解。

当然,他会被要求纠正一个关键的生产错误。他会到处搜索,可能不会注意到这一点。

我们应该总是为下一个人编码,他可能不如我们聪明。对我来说,这是唯一要记住的事情。

这意味着我们使用明显的语言特征并避免其他语言特征。

一切顺利,西尔万。

于 2009-05-07T21:34:04.647 回答
0

有点跑题了,但是如果您像这样在 vb.net 中使用相同的示例

dim someString as string
someString = MagicFunction()
if not string.IsNullOrEmpty(someString) and someString.Length > 3 then
    ' normal string, do whatever
else
    ' do someting else
end if

这会在一个空(无)字符串上爆炸,但在 VB.Net 中,您将其编码如下,在 C# 中做同样的事情

dim someString as string
someString = MagicFunction()
if not string.IsNullOrEmpty(someString) andalso someString.Length > 3 then
    ' normal string, do whatever
else
    ' do someting else
end if

添加 andalso 使它的行为方式相同,而且它读起来更好。作为同时进行 vb 和 c' 开发的人,第二个 vb 显示登录名略有不同,因此更容易向某人解释存在差异等。

德鲁克斯

于 2009-05-08T08:58:00.773 回答