在C#中,(对于其他语言,可以随意回答),运行时按什么顺序评估逻辑语句?
例:
1 2 3 4 5
| DataTable myDt = new DataTable();
if (myDt != null && myDt.Rows.Count > 0)
{
//do some stuff with myDt
} |
运行时首先评估哪个语句-
要么:
?
是否有一段时间编译器会向后评估该语句? 也许当涉及到"或"运算符时?
& 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,如此处其他人所述,如果可以在评估所有子表达式之前确定结果,它将尽早停止。
&被称为逻辑按位运算符,它将始终评估所有子表达式。
因此:
如果a返回true,则只会调用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
-
用文字5和GetSummary的结果调用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 |