前几日在浏览stackoverflow网站时,偶然看到别人提的“How to avoid ‘if’ chains” 的问题,觉得这是一个编程人员在编程时很容易就碰到的问题,而且我自己在看一些源码时也遇到过这种编程方式,因此,对这个问题进行一点总结。
if嵌套的情况很多,下面列出一些情况,并给出了相对来说比较简洁的书写方式以供参考:
1、使用一个guard来使用代码变得平坦
a、代码如下:
if (ok)
{
DoSomething();
}
else
{
_log.Error("oops");
return;
}
可以替换成:
if (!ok)
{
_log.Error("oops");
return;
}
DoSomething(); //notice how this is already farther to the left than the example above
b、代码如下:
ok = DoSomething1();
if (ok)
{
ok = DoSomething2();
if (ok)
{
ok = DoSomething3();
if (!ok)
{
_log.Error("oops"); //Tip of the Arrow
return;
}
}
else
{
_log.Error("oops");
return;
}
}
else
{
_log.Error("oops");
return;
}
可以改写成:
ok = DoSomething1();
if (!ok)
{
_log.Error("oops");
return;
}
ok = DoSomething2();
if (!ok)
{
_log.Error("oops");
return;
}
ok = DoSomething3();
if (!ok)
{
_log.Error("oops");
return;
}
ok = DoSomething4();
if (!ok)
{
_log.Error("oops");
return;
}
2、最后有非条件执行代码的情况,伪代码如下:
bool conditionA = executeStepA();
if (conditionA){
bool conditionB = executeStepB();
if (conditionB){
bool conditionC = executeStepC();
if (conditionC){
...
}
}
}
executeThisFunctionInAnyCase();
函数executeStepX当且仅当前面的条件成立时才执行,而函数executeThisFunctionInAnyCase则在最后必需执行,而不管其它条件是否成立。
a、使用条件与(&&),利用条件短路的特性
if (executeStepA() && executeStepB() && executeStepC()){
...
}
executeThisFunctionInAnyCase();
b、使用finally
try
{
bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;
}
finally
{
executeThisFunctionInAnyCase();
}
c、将条件执行用一个函数包起来
void foo()
{
bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;
}
void bar()
{
foo();
executeThisFunctionInAnyCase();
}
d、使用goto语句
int foo() {
int result = /*some error code*/;
if(!executeStepA()) goto cleanup;
if(!executeStepB()) goto cleanup;
if(!executeStepC()) goto cleanup;
result = 0;
cleanup:
executeThisFunctionInAnyCase();
return result;
}
e、利用条件的传递
bool condition = true; // using only one boolean variable
if (condition) condition = executeStepA();
if (condition) condition = executeStepB();
if (condition) condition = executeStepC();
...
executeThisFunctionInAnyCase();
f、使用异常
try {
executeStepA();
executeStepB();
executeStepC();
}
catch (...) {
executeThisFunctionInAnyCase();
}
g、使用假循环
while(true)
{
bool conditionA = executeStepA();
if (!conditionA) break;
bool conditionB = executeStepB();
if (!conditionB) break;
bool conditionC = executeStepC();
if (!conditionC) break;
break; //important
}
executeThisFunctionInAnyCase();
h、利用对象的生命周期
class MyContext
{
~MyContext()
{
executeThisFunctionInAnyCase();
}
}
void MainMethod()
{
MyContext myContext = new MyContext();
bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;
//DoSomethingNoMatterWhat will be called when myContext goes out of scope
}
其中,最简单的是利用条件短路,而最复杂的是利用对象的生命周期。总结了这此情况和方法供大家参考,当然,可能还有很多其它的情况和处理方法,希望读者踊跃留言。