布尔逻辑的可维护性-是否需要语句嵌套?


11

其中哪一个对可维护性更好?

if (byteArrayVariable != null)
    if (byteArrayVariable .Length != 0)
         //Do something with byteArrayVariable 

要么

if ((byteArrayVariable != null) && (byteArrayVariable.Length != 0))
  //Do something with byteArrayVariable 

我更喜欢阅读和编写第二篇文章,但我想起在代码中阅读完整内容是,这样做不利于可维护性。

这是因为if如果第一部分为假,并且并非所有语言都这样做,则您依赖语言来不评估第二部分。(第二部分如果使用null评估,将引发异常byteArrayVariable。)

我不知道这是否真的值得担心,我想就这个问题提供一般反馈。

谢谢。


1
第一种形式存在悬挂的风险
JBRWilkinson 2010年

只是好奇,您使用什么语言?
STW 2010年

@STW-我们使用C#,并且在Delphi中有一些旧代码。
瓦卡诺

2
很高兴知道。我不熟悉Delphi,但是在C#中,您可以对&&||操作员执行短路评估充满信心。从一种语言切换到另一种语言通常会有些麻烦,因此一定要坚定地进行代码审查以帮助发现这些小问题。
STW 2010年

尽管这里有许多答案,但我发现第二个更具可读性,第一个更容易调试。在这种情况下,我仍将使用第二个,因为您正在检查易于调试的东西。但总体上要小心。
Magus 2014年

Answers:


30

我认为第二种形式很好,也可以更清楚地表示您要执行的操作。你说...

我记得在读完代码后,这样做对维护性不利。这是因为如果第一部分为假,并且并非所有语言都这样做,则您依赖该语言不评估if的第二部分。

是否所有语言都可以这样做。您使用的是一种特定的语言,因此只有种语言能够做到这一点才有意义。否则,您实际上是在说您不应该使用特定语言的功能,因为其他语言可能不支持这些功能,这很愚蠢。


12
同意 为什么我的代码复制到另一种语言时是否会运行相同的代码呢?
Tim Goodman 2010年

16

我很惊讶没有人提到它(希望我不会误解这个问题),但是两种都糟透了!

更好的选择是使用早期退出(如果没有其他代码应执行,则在代码的早期放置一个return语句)。这假定您的代码重构得相对好,并且每种方法都有一个简洁的目的。

在那时,您将执行以下操作:

if ((byteArrayVariable == null) || (byteArrayVariable.Length != 0)) {
  return; // nothing to be done, leaving
}

// Conditions met, do something

它可能看起来很像验证-就是这样。它可以验证该方法满足其条件的条件-您提供的两个选项都将前提条件检查中的实际逻辑隐藏了下来。

如果您的代码是很多意大利面条(looong方法,很多嵌套的ifs,它们之间散布着逻辑,等等),那么您应该关注更大的问题,即在较小的样式问题之前使代码成形。根据您的环境和混乱的严重程度,有一些有用的工具可以帮助您(例如,Visual Studio具有“提取方法”重构功能)。


正如吉姆(Jim)所提到的,关于如何设计早期退出市场仍有争论的余地。上面的替代方法是:

if (byteArrayVariable == null) 
  return; // nothing to be done, leaving

if (byteArrayVariable.Length != 0)
  return;

// Conditions met, do something

1
我同意返回,而不是包装好的逻辑,但是同一个人将对使用||使用相同的论点。至于&&。
MIA 2010年

14

不要浪费时间试图为每一个非此情况而设的陷阱。如果您可以取消数据或条件的资格,请尽快这样做。

if (byteArrayVariable == null) Exit;
if (byteArrayVariable.Length == 0) Exit;
// do something

这使您可以更轻松地适应新条件的代码

if (byteArrayVariable == null) Exit;
if (byteArrayVariable.Length == 0) Exit;
if (NewCondition == false) Exit;
if (NewerCondition == true) Exit;
// do something

2
+1是,是,是。如此简单的逻辑不应导致困难的代码。您的(问问者)直觉应该告诉您这一点。
工作

11

您的示例是一个很好的示例,说明了为什么嵌套ifs对于大多数正确支持布尔比较的语言都是不好的方法。嵌套ifs创建会导致您的意图完全不清楚的情况。是否要求第二个if紧随第一个之后?还是仅仅是因为您尚未在其中进行其他操作?

if ((byteArrayVariable != null) && (byteArrayVariable.Length != 0))
  //Do something with byteArrayVariable 

在这种情况下,这些几乎必须在一起。他们充当了警卫,以确保您不执行会导致异常的操作。使用nested ifs,可以由您来决定跟随的人这两者是代表两部分的守卫还是其他分支逻辑。通过将它们合并为一个,if我要说明这一点。在不应该进行的地方进行操作要困难得多。

对于某人愚蠢的断言“并非所有语言都起作用”的愚蠢断言,我将始终倾向于明确表达我的意图。猜猜是什么... throw也不是所有语言都适用,这是否意味着我在用C#或Java进行编码时不应该使用它,而是应该依靠返回值来发出问题信号?

所有这一切说,这是一个很大更具可读性反其道而行,就回到该方法的出其中任意一个不能满足作为STW他们回答说。


可能有两个以上条件保证它们自己的函数返回空值。
工作

3

在这种情况下,您的两个子句直接相关,因此最好使用第二种形式。

如果它们不相关(例如,一系列在不同条件下的保护子句),那么我更喜欢第一种形式(或者我将重构出一个名称,该名称代表复合条件实际代表的方法)。


1

如果您在Delphi中工作,通常第一种方法会更安全。(对于给定的示例,使用嵌套的ifs并没有太多好处。)

Delphi允许您通过编译器开关指定布尔表达式是求值还是“短路”。方式1(嵌套ifs)允许您确保仅当(且严格)第一个子句的值为true时,第二个子句才执行。


1
在Delphi开发的23年中,我从未更改“ Complete boolean eval”选项。如果我将代码运送到其他地方,则可以在设备中放入{$ BOOLEVAL OFF}或{$ B-}。
格里

我也不。我也总是使用范围检查...但是其他人则没有。而且除了从性能的角度来看,它没有什么区别,因为您应该在布尔表达式中使用的函数中使用副作用。我敢肯定有人在那里!
Frank Shearar 2010年

@Gerry:同意。您可能希望进行全面评估的唯一原因是副作用-而有条件的副作用是个坏主意!
洛伦·佩希特尔

只是重新阅读我的评论23年应该是13年!我没有Tardis
Gerry,

1

第二种样式可能会在VBA中产生适得其反的效果,因为如果第一个测试是生成对象,它将仍然进行第二个测试并出错。在处理对象验证时,我只是习惯了在VBA中始终使用第一种方法。


2
那是因为VBA是一种可怕的语言
Falmarri 2010年

@Falmarri,它有一些可怕的东西(还有一些好东西)。如果我有德鲁特,我会修理很多东西。

2
缺少短路布尔值评估比什么都更重要。不知道为什么他们没有开始。OrElse和AndAlso的VB.NET“修复”有点烦人,但可能是在不破坏向后兼容性的情况下进行处理的唯一选择。
JohnFx 2010年

1

第二种形式更具可读性,尤其是在每个子句周围使用{}块的情况下,因为第一种形式将导致嵌套的{}块和多级缩进,这可能使阅读困难(您必须计算缩进空间弄清楚每个块的结束位置)。


0

我发现它们都可读,并且我不接受这样的论点,即如果您要切换语言,则应该担心代码的可维护性。

在某些语言中,第二个选项的效果更好,因此这将是显而易见的选择。


0

我和你在一起; 我是第二种方式。对我来说,从逻辑上讲更清楚。对于某些语言会执行第二部分的担心,即使第一部分的结果为false,这对我来说似乎有点愚蠢,因为我一生中从未编写过以“某些语言”运行的程序。我的代码似乎总是以一种特定的语言存在,该语言要么可以处理该构造,要么不能。(如果我不确定特定语言是否可以处理它,那是我真正需要学习的东西,不是吗。)

在我看来,第一种方法的危险在于,if如果我不是故意这样做的话,它会使我容易被意外地放入嵌套块之外的代码。诚然,这几乎不是一个大问题,但似乎比为我的代码是否与语言无关担心更合理。


0

我更喜欢第二种选择,因为它更具可读性。

如果您要实现的逻辑更加复杂(检查字符串不是null且不为空只是一个例子),则可以进行有用的重构:提取布尔函数。我在“代码完成”备注上使用@mipadi(“是否所有语言都可以...”)如果您的代码读者对在提取的函数内部不感兴趣,则该命令对布尔操作数求值成为它们的一个有争议的问题。


0
if ((byteArrayVariable != null)
 && (byteArrayVariable.Length != 0)) {
    //Do something with byteArrayVariable 

但这基本上是第二种选择。

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.