如果代码中没有条件判断、循环或者其他控制流程的语句,那么它的可读性会变得很好。而加入跳转和分支等控制流转部分会降低代码的可读性。
本章主要从代码的控制流转部分入手,来讨论如何让其变得可读。
把代码的控制流转部分修改的越自然越好,使得读者不用停下来,回头重读代码。
1 判断时:变量放左,常量放右
我们询问一个人的年龄的时候,
是问“请问你的年龄大于18岁吗”,
if(age>18)
而不是“请问18岁小于等于你的年龄吗?”,
if(18<=age)
计算机里也是遵从这样的表示方式:判断的左侧是趋于变化的值,判断的右侧是趋于常量的值。
ps: if(null==object),把null放左边,用于排除漏写一个等号的情况
但是现在IDE(Visual studio)会替你检查null=object这种情况,所以大可不必再坚持这种写法
2 if/else 语句块的顺序
比如同样的判断逻辑,你可以这样写
//先处理一致情况 if (a == b) { // 处理一致情况 } else { // 处理不一致情况 }
也可以这样写
if (a!=b) { // 处理不一致情况 } else { // 处理一致情况 }
在阅读本文之前,你可能对处理顺序不怎么在意。下面是我们给出的一些建议:
- 首先处理正逻辑而不是负逻辑,例如 if(ok),而不是if(!ok)
- 首先处理掉简单的情况,这有利于让if和else处理代码在同一个屏幕内可见
- 先处理有趣的情况或者是可疑的情况,这有利于第一时间回答读者的疑问
这些建议有时候会出现冲突,比如可疑的情况是负逻辑等,这个时候嘚取决于你的判断了。
比如可疑的情况 if(隔壁老王家的孩子!=亲生的)
比如更危险的 if(操作系统日志存在==false)
3 仅当处理代码简单的时候,使用三元运算符
来个例子
//先处理一致情况 if (a == b) { // 处理一致情况 } else { // 处理不一致情况 }
使用三元运算符可以把他们放到一行里面
a==b? 处理一致情况: 处理不一致情况
三元运算符其实就是对if/else的一种紧凑写法,但是它把多行代码凝缩到一行里面写法的代价就是可能造成阅读混乱并且难以调试。
是否使用三元运算符取决于你if/else代码块是否简单,比如只是从两个值中做出选择。
好的改造例子 GOOD
// if/else 例子 if (hour>=12) { timeString += "pm"; } else { timeString += "am"; } //改成三元运算符的例子 timeString += hour >= 12 ? "pm" : "am";
不好的改造例子 BAD
// if/else原始例子,代码自然易读 if (exponent >= 0) { return mantissa * (1 << exponent); } else { return mantissa / (1 << -exponent); } //改成了三元运算之后,代码挤到一行里降低了可读性 return exponent>=0?mantissa * (1 << exponent):return mantissa / (1 << -exponent);
指路明灯
默认情况下都使用if/else。三元运算符只有在最简单的情况下(比如值二选一)使用。
相对于追求最小化的代码行数,一个更好的建议是最小化读者阅读代码的时间。
4 避免do->while
do->while的奇怪之处在于一个代码块的是否执行的条件,是在代码执行过之后再判断。
而且我们通常是从前往后阅读代码,但是do->while模式下,我们常常还要回过头再看一遍被保护的代码。
通常来讲,判断语句应该出现在它所“保护”的代码之前。
先判断,符合条件再执行,这是if、while、for等流程控制语句的执行方式。
对于读者来讲,会先读到迭代条件,然后再读到代码块,因此更加易读。
但是仅仅为了去掉do->while,而把代码块提到迭代外面先执行一遍是非常愚蠢的做法。
//这是非常愚蠢的做法,试着去优化吧 // do代码块 while (判断) { // 重复 do代码块 }
5 从函数中提前返回,来最小化嵌套
我们想要单一的程序出口的动机是确保函数结尾时的清理代码被调用,
但是在c#中,我们可以使用try->finally、using语句,来保证函数结尾时的调用清理代码。
使用提前返回的机制,可以把函数的嵌套层级变浅。
来个例子
static bool checkUserAuthority() { bool a, b, c, d, e; if (a) { if (b) { if (c) { if (d) { if (e) { return true; } } } } } return false; }
使用 提前返回,从嵌套的泥淖中解脱出来
static bool checkUserAuthority() { bool a, b, c, d, e; if (!a) return false; if (!b) return false; if (!c) return false; if (!d) return false; if (!e) return false; return true; }