C#逻辑顺序和编译器行为

时间:2008-08-07 20:30:01

标签: c# language-agnostic compiler-construction logic

在C#中,(可以随意回答其他语言),运行时评估逻辑语句的顺序是什么?

示例:

DataTable myDt = new DataTable();
if (myDt != null && myDt.Rows.Count > 0)
{
    //do some stuff with myDt
}

运行时首先评估哪个语句 -

myDt != null

或:

myDt.Rows.Count > 0

是否有时候编译器会向后评估语句?也许当涉及“OR”运算符时?


  

&安培;被称为逻辑按位运算符,并将始终评估所有子表达式

什么时候使用按位运算符而不是“短路布尔值”的好例子?

18 个答案:

答案 0 :(得分:16)

C#:从左到右,如果找到不匹配(评估为false),则处理停止。

答案 1 :(得分:9)

“C#:从左到右,如果找到匹配(评估为真),则处理停止。”

僵尸羊是错的,没有足够的代表向下投票。

问题在于&&运算符,而不是||操作

在&&如果找到FALSE,评估将停止。

在||的情况下如果找到TRUE,评估将停止。

答案 2 :(得分:8)

我意识到这个问题已经得到解答,但我想提出与该主题相关的其他一些信息。

在C ++这样的语言中,你实际上可以超载&&amp ;;的行为。和||运营商,强烈建议您不要这样做。这是因为当您重载此行为时,最终会强制对操作的两端进行评估。这有两件事:

  1. 它打破了惰性评估机制,因为重载是一个必须调用的函数,因此在调用函数之前会对这两个参数进行求值。
  2. 不保证所述参数的评估顺序,并且可以是编译器特定的。因此,对象的行为方式与问题/上一个答案中列出的示例中的行为方式不同。
  3. 欲了解更多信息,请阅读Scott Meyers的书籍More Effective C++。干杯!

答案 3 :(得分:6)

<强> vb.net

if( x isNot Nothing AndAlso x.go()) then
  1. 评估从左到右进行
  2. AndAlso 运算符确保只有当左侧为TRUE时,才会评估右侧(非常重要,因为ifx不是x.go会崩溃)
  3. 你可以在vb中使用而不是和Also。在这种情况下,左侧也会先被评估,但无论结果如何,都会评估右侧。

    最佳实践:始终使用AndAlso,除非你有充分的理由不去。


    有人在跟进中询问为什么或何时使用And而不是AndAlso(或&amp;而不是&amp;&amp;): 这是一个例子:

    if ( x.init() And y.init()) then
       x.process(y)
    end 
    y.doDance()
    

    在这种情况下,我想初始化X和Y.必须初始化Y才能使y.DoDance能够执行。但是,在init()函数中我还做了一些额外的事情,比如检查一个套接字是否打开,只有当它运行正常时,对于两者,我应该继续执行x.process (y)的

    同样,这可能不是必需的,并且在99%的情况下都不优雅,这就是为什么我说默认应该是使用 AndAlso

答案 4 :(得分:5)

@shsteimer

  

概念谦虚是指运营商重载。在声明中:   ...   首先评估A,如果评估为false,则从不评估B.这同样适用于

这不是运算符重载。运算符重载是允许您为运算符定义自定义行为的术语,例如*,+,=等。

这可以让你编写自己的“Log”类,然后执行

a = new Log(); // Log class overloads the + operator
a + "some string"; // Call the overloaded method - otherwise this wouldn't work because you can't normally add strings to objects.

这样做

a() || b() // be never runs if a is true

实际上称为Short Circuit Evaluation

答案 5 :(得分:4)

ZombieSheep已经死了。可能正在等待的唯一“问题”是,只有在使用&amp;&amp;和运营商。当使用&amp;运算符,每次都会计算两个表达式,无论其中一个或两个都是否为false。

if (amHungry & whiteCastleIsNearby)
{
   // The code will check if White Castle is nearby
   // even when I am not hungry
}

if (amHungry && whiteCastleIsNearby)
{
   // The code will only check if White Castle is nearby
   // when I am hungry
}

答案 6 :(得分:4)

请注意&amp;&amp;和和&amp;关于你的表达有多少被评估。

&安培;&安培;被称为短路布尔AND,并且如其他人所指出的那样,如果可以在评估所有子表达式之前确定结果,则会提前停止。

&安培;被称为逻辑按位运算符,将始终评估所有子表达式。

因此:

if (a() && b())

如果 a 返回 true ,则只会调用 b

但是,这个:

if (a() & b())

将始终同时调用 a b ,即使调用 a 的结果为false,因此已知 false ,无论调用 b 的结果如何。

||存在同样的差异和|运算符。

答案 7 :(得分:4)

某些语言有一些有趣的情况,其中表达式以不同的顺序执行。我特别想到Ruby,但我确信他们是从其他地方借来的(可能是Perl)。

逻辑中的表达式将保持从左到右,但例如:

puts message unless message.nil?

以上将评估“message.nil?”首先,如果它的计算结果为false(除非是在条件为false而不是true时执行除外),“puts messages”将执行,它将消息变量的内容输出到屏幕。

这有时是一种有趣的构建代码的方式......我个人喜欢将它用于非常短的1个衬里,如上所述。

编辑:

为了使它更清晰,以上内容与:

相同
unless message.nil?
  puts message
end

答案 8 :(得分:2)

左边的一个,如果为空则停止。

编辑:在vb.net中,它将评估两者并可能抛出错误,除非您使用AndAlso

答案 9 :(得分:2)

概念谦虚是指运营商重载。在声明中:

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

首先评估A,如果评估为false,则永远不评估B.这同样适用于

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

首先评估A,如果评估为真,则永远不评估B.

这个概念,重载,适用于(我认为)所有C风格的语言,以及许多其他语言。

答案 10 :(得分:1)

当事情全部符合要求时,它们会从左到右执行。

当事物嵌套时,它们是从内到外执行的。这可能看起来令人困惑,因为通常什么是“最里面的”在线的右侧,所以看起来它正在倒退......

例如

a = Foo( 5, GetSummary( "Orion", GetAddress("Orion") ) );

事情就是这样:

  • 使用文字GetAddress
  • 致电"Orion"
  • 使用文字GetSummary"Orion"的结果
  • 致电GetAddress
  • 使用文字Foo5的结果
  • 致电GetSummary
  • 将此值分配给a

答案 11 :(得分:1)

我喜欢猎户座的回应。我将添加两件事:

  1. 从左到右仍然适用
  2. 内部到外部确保在调用函数之前解析所有参数
  3. 假设我们有以下示例:

    a = Foo(5, GetSummary("Orion", GetAddress("Orion")),
               GetSummary("Chris", GetAddress("Chris")));
    

    以下是执行顺序:

    1. GetAddress("Orion")
    2. GetSummary("Orion", ...)
    3. GetAddress("Chris")
    4. GetSummary("Chris", ...)
    5. Foo(...)
    6. 分配给a
    7. 我不能谈论C#的法律要求(虽然我在写这篇文章之前使用Mono测试了一个类似的例子),但这个顺序在Java中是有保证的。

      只是为了完整性(因为这是一个与语言无关的线程),还有像C和C ++这样的语言,除非有序列点,否则无法保证顺序。参考文献:12。然而,在回答线程的问题时,&&||是C ++中的序列点(除非过载;也请参阅OJ的优秀答案)。一些例子:

      • foo() && bar()
      • foo() & bar()

      &&案例中,foo()保证在bar()之前运行(如果后者全部运行),因为&&是一个序列点。在&的情况下,没有做出这样的保证(在C和C ++中),确实bar()可以在foo()之前运行,反之亦然。

答案 12 :(得分:1)

Nopes,至少C#编译器不能向后工作(在&amp;&amp;或||中)。它是从左到右。

答案 13 :(得分:1)

  

什么时候使用按位运算符而不是“短路布尔值”的好例子?

假设您有标记,例如文件属性。假设您已将READ定义为4,将WRITE定义为2,将EXEC定义为1.在二进制中,即:

READ  0100  
WRITE 0010  
EXEC  0001

每个标志都有一个位设置,每个标志都是唯一的。按位运算符允许您组合这些标志:

flags = READ & EXEC; // value of flags is 0101

答案 14 :(得分:0)

你使用&amp;当你特别想要评估所有子表达式时,很可能是因为它们有你想要的副作用,即使最终结果是 false 因此也不会执行然后部分 if -statement。

请注意&amp;和|对按位掩码和布尔值进行操作,不仅适用于按位运算。它们按位称为,但它们是在C#中为整数和布尔数据类型定义的。

答案 15 :(得分:0)

@csmba

  

有人在跟进中询问为什么或何时使用And而不是AndAlso(或者&amp;而不是&amp;&amp;):这是一个例子:

if ( x.init() And y.init()) then
   x.process(y)
end 
y.doDance()
     

在这种情况下,我想初始化X和Y.必须初始化Y才能使y.DoDance能够执行。但是,在init()函数中我还做了一些额外的事情,比如检查一个套接字是否打开,只有当它运行正常时,对于两者,我应该继续执行x.process(y)。

我认为这很令人困惑。尽管您的示例有效,但这并不是使用And的典型情况(我可能会以不同的方式编写它以使其更清晰)。 And(大多数其他语言中的&)实际上是按位和操作。您可以使用它来计算位操作,例如删除标志位或屏蔽和测试标志:

Dim x As Formatting = Formatting.Bold Or Formatting.Italic
If (x And Formatting.Italic) = Formatting.Italic Then
    MsgBox("The text will be set in italic.")
End If

答案 16 :(得分:0)

我听说编译器在某处工作,但我不确定这是多么真实。

答案 17 :(得分:0)