假设我有这样的伪代码:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}

executeThisFunctionInAnyCase();

函数executeStepX当且仅当前一个成功时执行。 在任何情况下,executeThisFunctionInAnyCase函数都应该在最后被调用。 我在编程方面是一个新手,所以很抱歉提出一个非常基本的问题:有没有一种方法(例如在C/ c++中)以代码易读性为代价,避免长if链产生那种“金字塔式代码”?

我知道如果我们可以跳过executeThisFunctionInAnyCase函数调用,代码可以简化为:

bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;

但是约束是executeThisFunctionInAnyCase函数调用。 break语句可以以某种方式使用吗?


当前回答

到目前为止,有50多个答案,但没有人提到我在这种情况下通常会怎么做!(例如,一个由几个步骤组成的操作,但使用状态机或函数指针表将是多余的):

if ( !executeStepA() )
{
    // error handling for "A" failing
}
else if ( !executeStepB() )
{
    // error handling for "B" failing
}
else if ( !executeStepC() )
{
    // error handling for "C" failing
}
else
{
    // all steps succeeded!
}

executeThisFunctionInAnyCase();

优点:

最终不会有巨大的缩进水平 错误处理代码(可选)出现在失败函数调用之后的那几行中

缺点:

如果有一个步骤不是仅仅包含在一个函数调用中,会变得很糟糕吗 如果除了“按顺序执行步骤,如果一个失败就终止”之外,还需要任何流,那么就会变得很糟糕。

其他回答

只是一个边注;如果if作用域总是导致返回(或循环中断),则不要使用else语句。这可以节省大量的缩进。

代码中的IF/ELSE链不是语言的问题,而是程序设计的问题。如果你能够重构或重写你的程序,我建议你在Design Patterns (http://sourcemaking.com/design_patterns)中寻找更好的解决方案。

通常,当您在代码中看到大量IF & else时,就有机会实现策略设计模式(http://sourcemaking.com/design_patterns/strategy/c-sharp-dot-net)或其他模式的组合。

我确信有替代方案来编写一长串if/else,但我怀疑它们除了对你来说看起来很漂亮之外不会改变任何东西(然而,情人眼里出佳人仍然适用于代码:-))。你应该关心这样的事情(6个月后,当我有一个新的条件,我不记得关于这个代码的任何事情,我是否能够轻松地添加它?)或者如果链发生变化,我将如何快速和无错误地实现它)

break语句可以以某种方式使用吗?

也许不是最好的解决办法,但你可以把你的陈述变成一种方式。While(0)循环并使用break语句而不是return。

假设你不需要单独的条件变量,反转测试并使用else-falthrough作为“ok”路径,将允许你获得更垂直的if/else语句集:

bool failed = false;

// keep going if we don't fail
if (failed = !executeStepA())      {}
else if (failed = !executeStepB()) {}
else if (failed = !executeStepC()) {}
else if (failed = !executeStepD()) {}

runThisFunctionInAnyCase();

省略失败的变量使代码在我看来有点太晦涩了。

在里面声明变量就可以了,不用担心= vs ==。

// keep going if we don't fail
if (bool failA = !executeStepA())      {}
else if (bool failB = !executeStepB()) {}
else if (bool failC = !executeStepC()) {}
else if (bool failD = !executeStepD()) {}
else {
     // success !
}

runThisFunctionInAnyCase();

这很模糊,但很紧凑:

// keep going if we don't fail
if (!executeStepA())      {}
else if (!executeStepB()) {}
else if (!executeStepC()) {}
else if (!executeStepD()) {}
else { /* success */ }

runThisFunctionInAnyCase();

另一种解决方案是通过宏hack定义习语。

 #define block for(int block = 0; !block; block++)

现在,“block”可以用break退出,与for(;;)和while()循环的方式相同。例子:

int main(void) {

    block {
       if (conditionA) {
          // Do stuff A...
          break; 
       }
       if (conditionB) {
          // Do stuff B...
          break; 
       }
       if (conditionC) {
          // Do stuff C...
          break; 
       }
       else {
         // Do default stuff...
       }
    } /* End of "block" statement */
    /* --->   The "break" sentences jump here */

    return 0;
} 

尽管使用了“for(;;)”结构,但“block”语句只执行了一次。 这些“块”可以用断句退出。 因此,if else if else if…避免使用句子。 最多,最后一个else可以挂在“块”的末尾,以处理“默认”情况。

该技术旨在避免典型的和丑陋的做{…} while(0)方法。 在宏块中,它定义了一个同样名为block的变量,该变量以这样一种方式定义,即恰好执行了一次for迭代。根据宏的替换规则,宏块定义中的标识符块不会被递归替换,因此block成为程序员无法访问的标识符,但在内部可以很好地控制for(;;)循环的“隐藏”。

此外:这些“块”可以嵌套,因为隐藏变量int块将有不同的作用域。