C#
Programming
以上的程式碼,比起使用for
做尋訪,foreach
看起來更為整潔,而foreach為什麼知道要做尋訪?以及與for迴圈相比需要有甚麼代價?
- 首先,先看看以下程式碼,他並不會編譯成功
編譯錯誤為: because 'int' does not contain a public definition for 'GetEnumerator'
看樣子是沒有對int
實作GetEnumator
,於是把程式改為以下的樣子:
還是一樣出現了錯誤: Integers.GetEnumerator()' must have a suitable public MoveNext method and public Current property
MoveNext
method與Current
property,如果知道設計模式,會知道其中有一個叫做Iterator pattern
,以上的錯誤訊息其實就是說我們若要對該資料型別使用foreach進行尋訪,則須對該資料型別實作Iterator pattern。於是再次進化以上的程式:
ConcreteAggregate: Integers
Iterator(): GetEnumerator()
ConcreteIterator: IntegerEnum
next()
: 傳回下一個元素,在C#中是以Current
來抓出目前元素
hasNext()
: 確認是否有下一個元素,在C#中是由MoveNext()
做確認
在Iterator裡有個跟C#上的實作差異
C# 已經有可以拿來實作Iterator pattern的interface,以上那張圖的Iterator
對應的是C#中的IEnumerator
,Aggreate
則是對應到IEnumerable
。
於是我們在將剛剛的程式進化一次
為了實現SRP原則,把計算邏輯與輸出分開,變成了:
enumerable_List
中的for
迴圈中,不管有沒有找到符合的數字,一定會把整個範圍跑一遍,再把數字存入List
List
會有額外的空間開銷實作Iterator pattern來解決兩個問題:
但人就是懶,一定要實作Iterator pattern嗎?答案是不用,我們可以用C#的語法糖 yield
該方法會怎麼運作?
outputDivide_foreach_List
呼叫enumerable_yield
時,enumerable_yield
的for
會持續計算直到找到符合的currentNum
,並在此時直接回傳到outputDivide_foreach_List
enumerable_yield
,繼續剛剛的計算,不會再次從頭計算。再看看以下程式
這支方法在運行到yield break
時,就會直接離開,並不會在回傳10