为什么在C#中同时存在该运算符的短路OR以及未短路的变化?


9

定期地,我对此感到奇怪:

短路OR总是返回与未短路OR运算符相同的值吗?

我希望短路OR总是可以更快地进行评估。那么,为确保一致性,C#语言中是否包含短路OR运算符?

我错过了什么?


9
相同的返回值-是。同样的副作用-不。
工作

2
假设f()引发异常,请考虑true || f()true | f()。你看得到差别吗?前一个表达式的计算结果为true,而后者的计算结果将引发异常。
scarfridge '04 -4-20

Answers:


25

这两个操作数用于不同的事物,它们来自C,它没有布尔类型。短路版本|| 仅适用于布尔值,而非短路版本| 与整数类型一起使用,按位或执行。它只是作为布尔的非短路逻辑运算而工作,它由一个单一的0或1位表示。

http://en.wikibooks.org/wiki/C_Sharp_Programming/Operators#Logical


10
+1的链接。当我读到这个问题时,我就像是“什么?” 因为afaik的正式名称是逻辑和按位的,或者不是短路和短路,这恰好是它们工作方式的副作用。
stijn 2011年

1
+1我看到“仅对布尔操作数进行操作”-我可能没有注意到差异,因为无论如何我只使用计算结果为布尔值的表达式
CarneyCode 2011年

2
我必须检查一下,但实际上,将|运算符应用于两个布尔值时,or就像在应用于两个整数值时一样||,被编译为CIL中的同一个运算符-与之不同的是,该运算符使用brtrue条件条件编译为CIL 跳。
quentin-starin 2011年

13

|(按位或)必须是非短路类型int。这是因为在几乎所有情况下,您都需要计算|表达式的两端以计算正确的结果。例如,的结果是7 | f(x)什么?

如果f(x)不评估,您将无法判断。

此外bool,当该运算符为时非短路时,使该运算符短路是不一致的int。顺便说一句,我认为我从未|有意用于逻辑比较,发现将其|称为逻辑运算符非常不便。

|| 但是,对于逻辑比较而言,短路评估效果很好。

即使对于C和C ++,这些运算符的起源也同样有效。


5

这是正确的,短路OR运算符(||)将始终返回与非短路OR运算符(|)相同的值。(*)

但是,如果第一个操作数为true,则短路运算符将不会导致对第二个操作数的求值,而非短路运算符将始终导致对两个操作数的求值。这可能会影响性能,有时还会产生副作用。

因此,两者都有用:如果您关心性能,并且对第二个操作数的求值不会产生任何副作用,或者(如果您不关心它们)则一定要使用短路运算符。但是,如果由于某种原因您需要第二个操作数的副作用,则应该使用非短路运算符。

您应使用非短路运算符的示例:

if( write_customer_to_database() != SUCCESS |
    write_supplier_to_database() != SUCCESS |
    write_order_to_database() != SUCCESS )
{
    transaction_rollback();
}

(*)某些真正变态的情况除外,在这种情况下,第一个操作数的值为false会导致第二个操作数的值为true而不是false。


2
+1但我想补充一点,除了使用函数来指示成功或失败(如您的示例):通常应避免具有副作用的函数……
Marjan Venema

1
是的,这可能就是为什么直到现在我从未使用过任何非短路操作器的原因,而且我从未有过这样的机会。
Mike Nakis 2011年

该示例取决于严格按从左到右的顺序对操作数进行求值。C#确实保证了这一点,但是许多类似的语言(包括C和C ++)却不能保证。
基思·汤普森

短路评估对于该特定示例是否有意义,因为如果其中任何一个失败,所有交易都会回滚?(我正在对通话的语义进行一些假设。)
Keith Thompson

@KeithThompson你是对的,非短路评估会导致不必要的处理,从这个意义上说,这个示例有点la脚,但它并不那么warrant脚以至于需要更改,因为事实仍然是短路评估write_customer_to_database()成功,则将永远不会调用其余的write _...函数,因此,如果成功,则可以正确地工作,而不是如果失败,则可以执行一些不必要的操作。
Mike Nakis 2011年

4

使用非短路变体有两个原因:

  1. 保持副作用(但是使用临时变量进行编码更清晰)

  2. 通过避免在短路中分叉来阻止定时攻击(如果第二个操作数是变量,则甚至可以提高运行时效率,但这是编译器可能进行的微优化)


这是提供的唯一正确的原因,我不知道为什么这不是最高票数被接受的答案……
Behrooz

2

如果运算符的右侧子句具有副作用,并且程序员希望在检查其返回值之前希望这两种副作用都发生。


5
真是的 请不要代码这样的...如果你依赖的副作用,有两种不同的表现,分配结果,并对其进行测试之后
康拉德·鲁道夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.