3

我经常在必要时这样做以防止空指针异常

// Example #1
if (cats != null && cats.Count > 0)
{
  // Do something
}

在 #1 中,我一直假设cats != null需要是第一位的,因为操作顺序是从左到右评估的。

但是,示例 #1 不同,现在我想做一些事情,如果对象是null或如果Count是零,因此我使用逻辑 OR 而不是 AND:

// Example #2
if (table == null || table.Rows == null || table.Rows.Count <= 0)
{
  // Do something
}

逻辑比较的顺序重要吗?或者我也可以颠倒顺序并获得相同的结果,例如示例#3?

// Example #3
if (table.Rows.Count <= 0 || table.Rows == null || table == null)
{
  // Do something
}

(顺便说一句,我意识到我可以像下面那样重写#2,但我认为它很乱,我仍然对 OR 运算符感到好奇)

// Example #4
if (!(table != null && table.Rows != null && table.Rows.Count > 0))
{
  // Do something
}
4

6 回答 6

11

在您提供的示例中:

if (table == null || table.Rows == null || table.Rows.Count <= 0)
{
  // Do something
}

...如果为 null ,则不会取消引用table.Rows,也不会取消引用。table.Rows.Counttables

这是因为,对于 C# 逻辑运算符,操作顺序很重要。C# 逻辑运算符是短路的- 它们从左到右计算,如果任何结果导致表达式的其余部分没有意义,则表达式的其余部分将不会被计算。

考虑这段代码:

bool A()
{
    return false;
}

bool B()
{
    return true;
}

//...

if (A() && B())
{
    // do something
}

要使 AND 子句为真,所有元素都必须为真。但是,A()返回 false,并且运行时(或者可能是这里的编译器,在优化步骤中,但我们不用担心......)根本不会评估B()

对于 OR ( ||) 表达式也是如此。如果子句中的任何元素为真,从左到右求值,则不会执行子句的其余部分。

于 2010-10-06T23:44:44.663 回答
2

是的,在这两种情况下都会发生短路,唯一的区别是 && 如果 LHS 为假则停止(因为整个表达式必须为假)而 || 如果 LHS 为真,则停止(因为整体表达式必须为真)。

您问题中的前两个示例是正确的,如果 table 或 table.Rows 为空,第三个示例将引发异常。

于 2010-10-06T23:58:54.640 回答
2

您应该注意,并非所有 C# 逻辑运算符都表现出短路行为(如上所述)。

您正在使用条件与运算符 (&&) 并且会短路。但是,与 (&) 运算符与没有短路的条件与 (Conditional-AND) 完全相同。

对于 OR 和 Conditional-OR 运算符也是如此。

例如:

//如果cats为null,无论顺序如何,这都会抛出。

if (cats != null & cats.Count > 0){ }

//这不会。由于短路。

if (cats != null && cats.Count > 0){ }

于 2010-10-07T02:52:08.007 回答
0

订单很重要。都是关于短路的。对于 ands,它遇到的第一个 false 停止评估,对于 ORs,它一遇到 true 就停止。

它会在第一次评估后短路,这就是为什么你没有得到空指针异常的原因。

当您考虑它时,请考虑为每个对象插入 null。

if (null== null || null.Rows == null || null.null.Count <= 0)
{
  // Do something
}

然后评估每个布尔值

if( true || null.Rows == null || null.null.Count <=0)

如果你看到的是真的,那就意味着停止。如果您点击“空”。声明你会崩溃。

说明崩溃的示例

if (null.null.Count <= 0 || null.Rows == null || null== null)
{
  // CRASH... Do something
}
于 2010-10-06T23:44:36.163 回答
0

第一种构造与第二种构造不同。第一个是在引用为 null 或 Count 为零时不执行任何操作时使用。当第二个构造为空或计数为零时,第二个构造会一些事情......要使第二个与第一个相同,您需要编写:

 if (table == null || table.Rows == null || table.Rows.Count <= 0 || ) 
 {}
 else
 { 
  // Do something 
 } 

并且顺序确实很重要,即使在您编写它的第二个中,如果表在尝试评估 table.Rows 时为空,它也会崩溃。

于 2010-10-06T23:46:02.197 回答
-1

顺序无所谓。

澄清:

您在 IF 语句中放置语句的顺序不会影响 IF 语句是否进入……以及结果。

正如另一位海报指出的那样,它会影响评估哪些内容,但这不会影响 AFAIK 的底线。

编辑@JonHanna

我想我是从 OP 表示他在需要时检查 NPE 之前的角度来看这个的(见他帖子的第一行)。因此,如果他的代码不会产生运行时错误,那么顺序就没有任何意义。我无法想象为什么有人会用“如果这个 IF 语句导致 NPE”的思考过程来编写一个 IF 语句,那么它就不会被评估......

于 2010-10-06T23:44:49.127 回答