关于不可知的语言:C#逻辑顺序和编译器行为

关于不可知的语言:C#逻辑顺序和编译器行为

C# logic order and compiler behavior

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

例:

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

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

1
myDt != null

要么:

1
myDt.Rows.Count > 0

是否有一段时间编译器会向后评估该语句? 也许当涉及到"或"运算符时?

& is known as a logical bitwise operator and will always evaluate all the sub-expressions

何时使用按位运算符代替"短路布尔值"的一个好例子是什么?


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


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

僵尸羊是错的,没有足够的代表来拒绝投票。

问题是关于&&运算符,而不是||。运营商。

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

对于||如果找到TRUE,则评估停止。


我知道这个问题已经得到解答,但是我想补充一点与该主题相关的信息。

在C ++之类的语言中,实际上您可以重载&&和||的行为。运算符,强烈建议您不要这样做。这是因为当您超载此行为时,您最终将迫使对操作双方进行评估。这有两件事:

  • 因为重载是必须调用的函数,所以它打破了延迟评估机制,因此在调用该函数之前先评估两个参数。
  • 不能保证评估这些参数的顺序,并且可以是编译器特定的。因此,对象的行为方式与问题/先前答案中列出的示例不同。
  • 有关更多信息,请阅读Scott Meyers的书《更有效的C ++》。干杯!


    vb.net

    1
    if( x isNot Nothing AndAlso x.go()) then
  • 从左到右进行评估
  • AndAlso运算符确保仅当左侧为TRUE时,才对右侧进行评估(非常重要,因为ifx无关x.go会崩溃)
  • 您可以在vb中使用And代替AndAlso。在这种情况下,左侧也将首先被评估,但是无论结果如何,右侧都将被评估。

    最佳实践:始终使用AndAlso,除非您有很好的理由不这样做。

    在后续活动中,有人问为什么或何时将有人使用And代替AndAlso(或&代替&&):
    这是一个例子:

    1
    2
    3
    4
    if ( x.init() And y.init()) then
       x.process(y)
    end
    y.doDance()

    在这种情况下,我想同时初始化X和Y。为了使y.DoDance能够执行,必须初始化Y。但是,在init()函数中,我还执行其他一些操作,例如检查套接字是否打开,并且只有在工作正常的情况下,我才应该继续执行x.process(y)。

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


    @shsteimer

    The concept modesty is referring to is operator overloading. in the statement:
    ...
    A is evaluated first, if it evaluates to false, B is never evaluated. The same applies to

    这不是运算符重载。运算符重载是一个术语,用于让您定义运算符的自定义行为,例如*,+,=等。

    这样您就可以编写自己的" Log"类,然后执行

    1
    2
    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.

    这样做

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

    实际上称为短路评估


    某些语言在有趣的情况下会以不同的顺序执行表达式。我特别在考虑Ruby,但是我确定他们是从其他地方(可能是Perl)借来的。

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

    1
    puts message unless message.nil?

    上面将评估" message.nil?"首先,然后,如果它的计算结果为false(除非与条件条件为false而不是true时执行一样),将执行" puts message",这会将message变量的内容打印到屏幕上。

    有时候,这是一种有趣的结构化代码的方式...我个人喜欢将其用于非常短的1个上述代码。

    编辑:

    为了更清楚一点,以上内容与以下内容相同:

    1
    2
    3
    unless message.nil?
      puts message
    end


    ZombieSheep已经死了。可能正在等待的唯一"陷阱"是,仅当您使用&&运算符时,这才是正确的。使用&运算符时,每次都会对这两个表达式进行求值,而不管一个或两个求值为false。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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
    }

    请注意,&&和&之间在计算表达式的多少方面有所不同。

    &&被称为短路布尔AND,如此处其他人所述,如果可以在评估所有子表达式之前确定结果,它将尽早停止。

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

    因此:

    1
    if (a() && b())

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

    但是,这:

    1
    if (a() & b())

    即使调用a的结果为false,因此无论调用b的结果如何,都将始终调用a和b。

    ||存在相同的差异和|运营商。


    谦虚是指操作员重载。在声明中:

    1
    2
    3
    if( A && B){
        // do something
    }

    首先评估A,如果评估为假,则永远不会评估B。同样适用于

    1
    2
    3
    if(A || B){
        //do something
    }

    首先评估A,如果评估为true,则永远不会评估B。

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


    左边的为空,然后停止。

    编辑:在vb.net中,它将同时评估这两者并可能引发错误,除非您使用AndAlso


    What is a good example of when to use the bitwise operator instead of the"short-circuited boolean"?

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

    1
    2
    3
    READ  0100  
    WRITE 0010  
    EXEC  0001

    每个标志设置一个位,并且每个标志都是唯一的。按位运算符使您可以组合以下标志:

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


    当所有事情都在线时,它们从左到右执行。

    当事物嵌套时,它们从内到外执行。这似乎令人困惑,因为通常"最内层"位于该行的右侧,因此似乎向后退了。

    例如

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

    事情像这样发生:

    • 用文字"Orion"调用GetAddress
    • 用文字"Orion"GetAddress的结果调用GetSummary
    • 用文字5GetSummary的结果调用Foo
    • 将此值分配给a

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

  • 从左到右仍然优先
  • 由内而外确保在调用函数之前解析所有参数
  • 假设我们有以下示例:

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

    执行顺序如下:

  • GetAddress("Orion")
  • GetSummary("Orion", ...)
  • GetAddress("Chris")
  • GetSummary("Chris", ...)
  • Foo(...)
  • 分配给a
  • 我无法谈论C#的法律要求(尽管在撰写本文之前,我曾使用Mono测试过类似的示例),但是Java保证了此顺序。

    仅仅为了完整性(因为这也是与语言无关的线程),还有C和C ++之类的语言,除非有序列点,否则无法保证顺序。参考:1、2。但是,在回答线程的问题时,&&||是C ++中的序列点(除非重载;另请参见OJ的出色回答)。下面是一些例子:

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

    &&情况下,由于&&是一个序列点,因此保证foo()bar()之前运行(如果后者完全运行)。在&情况下,(在C和C ++中)没有这样的保证,实际上bar()可以在foo()之前运行,反之亦然。


    不,至少C#编译器不会向后工作(在&&或||中)。从左到右。


    D编程语言在进行短路时从左至右进行评估,并且不允许&&和'||'重载运营商。


    当您特别想评估所有子表达式时,可以使用&,这很可能是因为它们具有所需的副作用,即使最终结果将为假,因此也不会执行if语句的then部分。

    请注意&和|不仅适用于按位运算,还适用于按位掩码和布尔值。它们被按位调用,但是在C#中为整数和布尔数据类型定义了它们。


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


    @csmba:

    It was asked in a followup why or when would anyone use And instead of AndAlso (or & instead of &&): Here is an example:

    1
    2
    3
    4
    if ( x.init() And y.init()) then
       x.process(y)
    end
    y.doDance()

    In this case, I want to init both X and Y. Y must be initialized in order for y.DoDance to be able to execute. However, in the init() function I am doing also some extra thing like checking a socket is open, and only if that works out ok, for both, I should go ahead and do the x.process(y).

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

    1
    2
    3
    4
    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

    推荐阅读