解讀經典《C#高階程式設計》第七版 Page38-45.核心C#.Chapter2
前言
控制流是語言中最基礎的部分,我們不談具體的細節,只講講一些關鍵和有趣的點。
01
流控制
條件語句:if, else if, else
if語句的使用非常值得細講,如何是好的使用習慣。有一點非常重要,就是儘可能的避免太多層次的巢狀,這將帶來可讀性災難。我自己的原則是,if巢狀一般不超過2層,最多不超過3層。可讀性是什麼?是指:不只是你自己寫的程式碼你自己能讀懂,更重要的是當別人接手你的程式碼的時候,別人能讀懂。
If巢狀導致的可讀性災難在Java程式裡非常常見,我看別人的遺留程式碼就是這個感受。一個原因是Java沒有像C#這樣的linq工具,以及一些語法糖,導致很多常用的計算也要自己寫if語句實現,這些程式碼再套在業務程式碼中,if層次就很多了,還有比如欄位定義都需要生成getter和setter方法(我的Java功力太淺薄,看到大家寫Java程式碼都是這麼寫,但卻不能理解為什麼一定要遵循這個範兒),取數判斷都是getXXX(),導致布林表示式程式碼看著一長串,程式碼太長又導致很多Java程式設計師會把一個if拆開成多個巢狀的if來寫。比如這個if層次達到了4層(這還不算多,我見過七八層的都有,但一時找不到更多巢狀的例子):
If巢狀層次多會導致什麼問題?就是多執行路徑的災難,一個最簡單的if else,如果達到3層巢狀,總的可能執行路徑就是2*2*2=8。你的程式要保證這8種執行可能性都被考慮到,這導致的結果往往是程式設計師放棄遵循嚴謹的邏輯,只考慮正常的業務邏輯,忽略異常的業務邏輯處理。還有些程式設計師程式設計習慣不好,只關注if 不關注else,這種程式設計師的程式碼裡,大量的if語句沒有else,往往就隱藏著很多的邏輯地雷。
對於if else的使用,我的使用習慣是:
- 寫下if時就要想到else怎麼處理,程式設計師要打造的是一個“執行容器”,控制容器邊界是他的基本職責。只完成需求而不關注“容器”邊界安全的程式設計師不是合格的程式設計師。
- 優先處理else,就是先處理異常的邏輯,並return,從而將 if else的寫法替換為if return,從而使得if else 巢狀層級-1。一段程式碼中,先後的多個if語句都使用這種方式,可使巢狀層級持續減少,可能原本需要五六層級的if巢狀,最後只需要一級if語句實現,程式碼健壯性和可讀性大大增強。
- 如果某些地方只需要寫if不需要else,但業務邏輯比較複雜,不是能很直觀的理解時,我會寫空else,並在else中加註釋,說明為什麼else為空。
條件語句:switch
有些人不喜歡使用switch,因為if else也能完成switch的功能,因此懶得去分辨該怎麼用switch。我對語言(以及框架)的使用原則不是最簡單的夠用就好,而是為每種語言特性找到適合它的使用場景,並堅持按最佳的使用方式編寫程式碼
Switch語法還有一種特殊用法是,多個空case語句以使多個值條件下執行同一段程式碼:
switch(str)
{
case "0":
case "1":
break;
default:
break;
}
迴圈語句:for,while,do…while,foreach
用的最多的,應該是foreach了,因為迴圈一個List是當今編寫C#程式碼中最常用的操作了。當你想使用集合的行號時,foreach就不夠用了,要用for語句了。非List的迴圈則會用while,而do…while我很少用,不是它不好用,而是while用習慣了,往往想不起去用do…while。這其實也是在提醒我們:為語言(和類庫)特性找到適合它的可明確表述的使用場景是很重要的,因為只有這個意識植入了你心底裡,才能在程式設計中自如的使用最合適的語言特性和類庫工具,而不是“都行”,如果遵循的是“都行”的態度,逐漸的你會偏向只使用一種最簡單的特性和工具。
迴圈還有幾個小知識點:
For,foreach中的變數可以使用型別推斷var,比如:
foreach(var user in list)
for(var i=0; i< 100; i++)
for迴圈可初始化多個值,比如:
for (int i = 0, j = 0; i < 100; i++, j = j + 2)
foreach迴圈集合時,不能更改集合項的值。如果要修改,可以使用for迴圈代替。但如果要在迴圈中刪除集合的某項,for迴圈也不行了,這個時候可以將集合進行“變身”,使得迴圈的“集合”和要處理的“集合”成為兩個不同的集合,是個技巧,比如:
跳轉語句:goto
C#中我從來沒用過goto。可以說c#中使用goto幾乎沒有什麼優點,唯一的一個明顯用途,是跳出雙層迴圈(後面有例子),goto使得跳出雙層迴圈非常方便,否則我們得自己使用一個獨立變數來控制跳出雙層迴圈。
跳轉語句:break
Break用於退出switch,以及退出for,foreach,while,do…while的迴圈。
跳轉語句:continue
Continue用於退出for,foreach,while,do…while的當前迭代。
跳轉語句:return
Return用於退出類的方法。
我們對比.Net和Java的語法,發現在goto、break、continue上是有區別的。Java沒有goto,而使用了break和continue的功能加強來替代goto的功能。而C#保留了goto,且不提供Java中break和continue中加強的功能。
.Net:
Java:
哪種方式更好呢?我更喜歡.Net的處理方式。.Net從實用主義出發,更直觀,但可能有些程式設計師會過度使用goto。而Java表達了語言開發者對Goto的完美厭惡和徹底禁絕,同時,對continue和break的擴充套件思路非常精妙(但break label稍稍有點彆扭)。
本來還想講列舉,結果發現流控制也講了不少,那麼列舉到下一篇再講。
列舉概念很簡單,但我覺得有必要討論的是列舉它簡單的語言定義,和它在實際應用時存在的鴻溝,應該如何填平的問題。
覺得文章有意義的話,請動動手指,分享給朋友一起來共同學習進步。
歡迎關注本人微信公眾號,更及時的關注最新文章(每週三篇原創文章,以及多篇專題文章):
附文: