【问题标题】:Order of operators in IF statementIF 语句中的运算符顺序
【发布时间】:2011-04-22 02:50:01
【问题描述】:

为了防止空指针异常,我经常这样做:

// 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
}

【问题讨论】:

    标签: c# if-statement nullpointerexception logical-operators


    【解决方案1】:

    在您提供的示例中:

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

    ...如果tables 为空,则table.Rowstable.Rows.Count 都不会被取消引用。

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

    考虑这段代码:

    bool A()
    {
        return false;
    }
    
    bool B()
    {
        return true;
    }
    
    //...
    
    if (A() && B())
    {
        // do something
    }
    

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

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

    【讨论】:

    • 旁注:VB 不会像这样使用And 短路运算符。如果你使用AndAlso,它会。
    • +1:如果您编辑并只给我答案的最后 6 行(包括回车),我会将您标记为答案。
    • @John:谢谢,但我不想这样做;我也在为未来的读者写作。标记对您最有帮助的答案。
    • @Jonathan Allen:天哪 +100!我一直想知道AndAlso 到底是为了什么!我鄙视 VB :( 但我从现在开始使用AndAlso 而不是And
    • @Jonathan,这实际上与 C# 没有什么不同,如果您使用 &amp;,它不会短路(其他 C 风格的语言也是如此,但使用按位和和在 C# 中使用布尔值和更清晰的布尔值规则)。
    【解决方案2】:

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

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

    【讨论】:

    • 我想他也是。我添加这个是因为我认为我可以把它说得更清楚,但我个人会给迈克尔打勾。
    【解决方案3】:

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

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

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

    例如:

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

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

    //这不会。由于短路。

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

      • 我认为你误解了我的目标。在第二个“构造”中,当它为空或计数为零时,我想 DO 做某事。
      • 如果是这种情况,那么第一个示例没有这样做,它在引用不为空时正在做某事。还是这些示例不应该代表相同的任务?如果是这种情况,那么唯一的错误是您需要颠倒顺序,因为顺序确实很重要,正如其他人也建议的那样......
      • 非常感谢查尔斯的帮助。很抱歉,您不清楚我的问题;我已经对其进行了修改,以更好地说明我的意思。其他人已经解决了我的预期问题。再次感谢。
      【解决方案5】:

      订单很重要。都是关于短路的。对于 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)
      

      如果您看到 true,则表示停止。如果您点击“空”。声明你会崩溃。

      举例说明崩溃

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

      【讨论】:

      • 这是错误的,恰恰相反。对于 AND,它命中的第一个 false 将停止评估,因为整个语句不可能为真;对于 OR,只要 any 部分为真,它就可以停止。
      • 是的,这有点错别字...现在已修复。
      【解决方案6】:

      顺序无关紧要。

      澄清:

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

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

      编辑@JonHanna

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

      【讨论】:

      • 空指针异常影响底线。颠倒问题中第一个示例中的顺序,这就是你得到的。
      猜你喜欢
      • 1970-01-01
      • 2015-02-08
      • 2015-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-04
      相关资源
      最近更新 更多