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

在C#中(并且随意为其他语言回答),运行时以什么顺序评估逻辑声明?

例:

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

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

myDt != null

要么:

myDt.Rows.Count > 0

Is there a time when the compiler would ever evaluate the statement backwards? Perhaps when an "OR" operator is involved?


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

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

0

18 答案

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

  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. Assigns to a

我不能谈论C#的法律要求(尽管在写这篇文章之前我曾经用Mono测试过一个类似的例子),但是这个顺序在Java中是有保证的。

And just for completeness (since this is a language-agnostic thread as well), there are languages like C and C++, where the order is not guaranteed unless there is a sequence point. References: 1, 2. In answering the thread's question, however, && and || are sequence points in C++ (unless overloaded; also see OJ's excellent answer). So some examples:

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

In the && case, foo() is guaranteed to run before bar() (if the latter is run at all), since && is a sequence point. In the & case, no such guarantee is made (in C and C++), and indeed bar() can run before foo(), or vice versa.

0
额外

如果它为空,则停止。

编辑:在vb.net它会评估两个,并可能抛出一个错误,除非你使用AndAlso

0
额外

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

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

puts message unless message.nil?

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

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

编辑:

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

unless message.nil?
  puts message
end
0
额外

@shsteimer

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

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

这可以让你编写你自己的'日志'类,然后做

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

is actually called Short Circuit Evaluation

0
额外

当事情全部在线时,它们从左到右执行。

当事物嵌套时,它们被内部执行到外部执行。这可能看起来很混乱,因为通常线的右侧是“最内层”,所以它看起来像是倒退了......

例如

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

事情发生像这样:

  • Call GetAddress with the literal "Orion"
  • Call GetSummary with the literal "Orion" and the result of GetAddress
  • Call Foo with the literal 5 and the result of GetSummary
  • Assign this value to a
0
额外

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

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

首先评估A,如果评估结果为假,则B从不评估。这同样适用于

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

首先评估A,如果评估结果为真,则B从未评估。

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

0
额外

vb.net </强>

if( x isNot Nothing AndAlso x.go()) then
  1. Evaluation is done left to right
  2. AndAlso operator makes sure that only if the left side was TRUE, the right side will be evaluated (very important, since ifx is nothing x.go will crash)

您可以在vb中使用,而不是。在这种情况下,左侧也会首先被评估,但右侧会得到评估,无论结果如何。

最佳实践:永远使用AndAlso,除非你有一个非常好的理由不为什么。


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

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

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

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

0
额外

我听说编译器有倒退的地方,但我不确定这是多么真实。

0
额外

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

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

READ  0100  
WRITE 0010  
EXEC  0001

每个标志都有一个位,每个标志都是唯一的。按位运算符让你组合这些标志:

flags = READ & EXEC; // value of flags is 0101
0
额外

ZombieSheep is dead-on. The only "gotcha" that might be waiting is that this is only true if you are using the && operator. When using the & operator, both expressions will be evaluated every time, regardless if one or both evaluate to 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
}
0
额外

Nopes, at least the C# compiler doesn't work backwards (in either && or ||). It's left to right.

0
额外

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

0
额外
正如其他人所说的那样,&&运算符上的短路发生在错误上。
额外 作者 Broam,

The D programming language Does do left-to-right evaluation with short circuiting and doesn't allow overloading of the && and '||' operators.

0
额外

You use & when you specifically want to evaluate all the sub-expressions, most likely because they have side-effects you want, even though the final result will be false and thus not execute your then part of your if-statement.

Note that & and | operates for both bitwise masks and boolean values and is not just for bitwise operations. They're called bitwise, but they are defined for both integers and boolean data types in C#.

0
额外

Note that there is a difference between && and & regarding how much of your expression is evaluated.

&& is known as a short-circuited boolean AND, and will, as noted by others here, stop early if the result can be determined before all the sub-expressions are evaluated.

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

因此:

if (a() && b())

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

然而,这是:

if (a() & b())

即使调用 a 的结果为false,并且因此已知为 false ,也会始终调用 a b >不管调用 b 的结果如何。

这与||有相同的区别和|运营商。

0
额外

“C#:从左到右,如果找到匹配(计算结果为true),则处理停止。”

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

The question is about the && operator, not the || operator.

In the case of && evaluation will stop if a FALSE is found.

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

0
额外
是的。你说得很对。尽管如此,我确实希望我的正确答案得到了正确的解释。当然,我不打算误导任何人。
额外 作者 ZombieSheep,

@csmba:

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

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).

I believe this is rather confusing. Although your example works, it's not the typical case for using And (and I would probably write this differently to make it clearer). And (& in most other languages) is actually the bitwise-and operation. You would use it to calculate bit operations, for example deleting a flag bit or masking and testing flags:

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
0
额外

我意识到这个问题已经得到了回答,但我想再提一点与这个主题相关的信息。

In languages, like C++, where you can actually overload the behaviour of the && and || operators, it is highly recommended that you do not do this. This is because when you overload this behaviour, you end up forcing the evaluation of both sides of the operation. This does two things:

  1. 它打破了懒惰的评估机制,因为重载是一个必须被调用的函数,因此在调用函数之前对这两个参数进行评估。
  2. 所述参数的评估顺序不能保证,并且可以是编译器特定的。因此,这些对象的行为方式与问题/以前的答案中列出的例子不同。

欲了解更多信息,请阅读Scott Meyers的书更有效的C ++ 。干杯!

0
额外