关于C#短路求值,哪种是最佳实践?
关于C#短路求值,哪种是最佳实践?
在另一个帖子中的一个回答和随后的评论辩论促使我提出了以下问题:\n在C#中,||和&&分别是逻辑运算符|和&的短路版本。
\n示例用法:\n
if (String.IsNullOrEmpty(text1) | String.IsNullOrEmpty(text2) | String.IsNullOrEmpty(text3)) { //... }
\n相对于:\n
if (String.IsNullOrEmpty(text1) || String.IsNullOrEmpty(text2) || String.IsNullOrEmpty(text3)) { //... }
\n从编码实践的角度来看,哪种更好并且为什么?\n注意:我确实意识到这个问题类似于这个问题,但我认为它值得进行语言特定的讨论。
C#中的短路求值是一种常见的编程技巧,用于在布尔条件中使用&&
和||
运算符。当我们只关心结果并且希望尽快知道结果时,这种技巧非常有用。而且,如果表达式没有副作用,也没有必要对每个表达式进行求值,因此我们几乎总是使用短路求值。
但是,当我们的表达式具有副作用并且需要对每个表达式进行求值时,我们应该使用&
和|
运算符。但是,我们应该避免在程序依赖于未满足布尔条件时必须发生的副作用的情况下使用&
和|
。
例如,下面的代码就是一个非常愚蠢的例子:
if (false & somethingThatUpdatesTheDatabase()) { /* ... */ }
在上述例子中,由于第一个条件为false,短路求值将导致不会对第二个条件进行求值。然而,由于我们使用的是&
运算符,somethingThatUpdatesTheDatabase()方法仍然会被调用,这是没有必要的。
因此,为了避免这种不必要的副作用,我们应始终使用&&
和||
运算符来进行短路求值。这样可以提高程序的性能,并确保只有在需要时才会发生副作用。
C#短路评估的最佳实践是什么?
短路评估是指在逻辑运算中,当结果可以通过检查前一部分条件来确定时,不再继续执行后续的条件判断。这种方式可以提高运行效率和减少不必要的计算。在C#中,使用逻辑运算符 && 和 || 进行短路评估。
在上述讨论中,某些情况下了在条件判断中使用位运算赋值操作符的情况。例如,当有一系列需要同时满足的条件时,可以使用位运算赋值操作符来简化代码。这种方式在代码可读性方面可能会稍逊一筹,但在某些情况下可以更加简洁和高效。
然而,对于密码验证的例子,使用短路评估是更为合适的选择。因为如果密码不满足最基本的要求,即长度为8个字符,那么是否包含数字和大小写字母就变得无关紧要。在这种情况下,可以将代码改为使用三行if语句来进行条件判断,如果一个条件不满足,则直接返回false,否则返回true。这样可以更好地控制返回的信息。
短路评估是一种在条件判断中提高效率和简化代码的方法。在某些情况下,可以使用位运算赋值操作符来简化多个条件的判断,但在其他情况下,短路评估可能更适合。选择合适的方法取决于具体的需求和代码的可读性要求。
关于C#的短路求值,最佳实践是什么?
简单回答:始终使用短路求值版本。没有任何理由不这样做。此外,通过使用短路求值,可以使代码更清晰,表达你的意图:逻辑求值。使用位操作(逻辑操作)意味着你只想进行位操作,而不是逻辑求值(尽管MSDN也将它们称为“逻辑操作”,当应用于布尔值时)。
此外,由于短路求值只评估需要评估的部分,它通常更快,并且可以编写以下代码:
bool nullorempty = str == null || str.Length == 0;
(请注意,为了解决这个特定问题,已经存在一个更好的函数,即`string.IsNullOrEmpty`,你在问题中也使用了它。)如果使用位逻辑操作,这段代码是不可能的,因为即使`str`是`null`,第二个表达式也会被评估,导致`NullReferenceException`。
编辑:如果你希望在逻辑上下文中发生副作用,请仍然不要使用位操作。这是一个典型的过于聪明的例子。代码的下一个维护者(甚至是你自己,在几周后)看到这段代码会想:“嗯,这段代码可以简化为使用条件运算符”,从而无意中破坏代码。我为负责修复此错误的人感到遗憾。
相反,如果你必须依赖副作用,请明确地表达它们:
bool hasBuzzed = checkMakeBuzz(); bool isFrobbed = checkMakeFrob(); bool result = hasBuzzed || isFrobbed;
确实,这需要三行代码而不是一行。但结果是更清晰的代码。
这是一个很好的回答,但你能把“位操作”改为“逻辑操作”,将“逻辑”改为“条件”吗?这是MSDN使用的术语。从技术上讲,两者都是“逻辑”的,但是双倍版本也是短路的。
“条件-与”运算符(&&)对其布尔操作数执行逻辑与操作,但只在必要时评估其第二个操作数。
完美的回答。对于副作用讨论的+1 - 同意,对于维护性,始终要明确。三行代码与维护噩梦,三行代码赢得胜利。
你的链接在某种程度上与你的术语说法相矛盾。实际上,我发现你是对的:MSDN在应用于布尔值时都将这两个运算符称为“逻辑”。我将在我的回答中反映这一点。
此外,即使你不认为短路求值是正确的做法,也请使用它,因为人们已经以这种方式编写C/C++代码30年了。这几乎已经成为共同法了。
但是你并没有编写C++代码。C++编译器为了避免分支预测失败的代价,需要经过相当艰巨的措施。在C#中,你总是得到一个分支。如果左操作数表达式预测不准确,你会付出巨大代价,在现代处理器上,||或&&运算符的速度会慢上五倍。始终进行测试。
我非常坚定地认为,这需要在编译器中进行修复,而不是在用户代码中。因为在用户代码中进行修复会导致(a)代码的保证减弱,以及(b)执行无法预测且有时无法进行基准测试的“优化”,从而(c)过早的优化,这通常会导致(d)悲观的结果。简而言之,这不是用户代码优化的一个好策略。这是一个优化编译器的工作。
嗯,我从来没有见过一个程序通过坚定的意见进行优化。这实际上是最糟糕的方法。
尽管很难相信,但这正是我之前的评论所说的。这是一个可怕的领域,不要指望用户来进行适当的优化,因为在这里收集可靠的数据非常困难。结果会得到基于意见的优化。更糟糕的是,它涉及与弱化语义的痛苦权衡。所以我对这样做非常谨慎。