本篇将圍繞 《試試IEnumerable的10個小例子》和《試試IEnumerable的另外6個小例子》給出的例子,總結一下對于
IEnumerable
接口的一些使用方法,希望讀者能夠從中獲得一些啟發。
架構類型的疊代
對于一個實作了
IEnumerable
接口的類型來說,開發中最常用的,就是把這個類型的對象放入到
foreach
等循環關鍵詞中進行疊代,周遊其中的元素進行處理。
這種周遊通常分為兩種目的:周遊和查找。
IEnumerable
及其泛型版本
IEnumerable<T>
定義了一個類型的“可疊代性”。這點很容易了解,系統中的很多集合類型都實作了該接口。
是以這些集合類型均可以采用
foreach
進行疊代周遊。但是每個集合類型的疊代方式和結果是不完全相同的,這取決于集合本身的特性。例如:
-
、List<>
和Stack<>
的疊代的順序不相同,因為資料結構本身要求是不同的Queue<>
-
和ConcurrentDictionary<,>
在疊代時的線程安全性是不同的,因為針對線程安全的設計是不同的Dictionary<,>
-
方法傳回一個會産生阻塞的消費者對象,BlockingCollection.GetConsumingEnumerable
是以,即使都是丢進
foreach
,但是效果也是不完全一樣的。使用這些,需要讀者對這些類型本身需要增進了解。
建議讀者在使用架構中實作了
IEnumerable
的類型時,一定要注意疊代的細節,可以通過MSDN上的文檔了解其特殊性。
Linq
Linq是一個說小不小的話題,這裡隻是說其中的 Linq To Object 部分内容。
通過Linq中提供的一些擴充方法,可以友善的控制對于一個
IEnumerable
對象的疊代方式。通過這些方法的應用,可以在很多時候避免複雜的條件和循環嵌套。
同時,Linq中抽象的Func和Action,也要求開發人員在平時的編寫過程中注意對于疊代本身的歸類和整理。
Where(IsLeapYear)
會比
Where(x=>(x % 4 == 0 && x % 100 != 0) || x % 400 == 0)
來的更加容易閱讀。
設計複雜的資料結構及其疊代算法
除了基礎的資料結構,開發過程中有時需要自定義一些集合類型。這些集合類型需要自己實作一個疊代過程。例如:二叉樹及其周遊,對清單進行分頁等等。
這些資料結構的疊代通常需要特定算法的支援。
在《試試IEnumerable的另外6個小例子》中關于樹的幾個例子便資料此類中。
本地函數
在C#7.0引入了本地函數之後,
IEnumerable
結合本地函數,快速實作自定義疊代過程的奇怪操作也就跟着出現。
通過這種操作可以在一個函數内采用一些以前不容易實作的方式實作一些操作:
- 将多重循環拉平
- 将多級條件判斷變為循環判斷
- 無需建立新的類就能快速生成一個上下文需要的特殊疊代算法
這相關的例子在《試試IEnumerable的10個小例子》中較多。
按照月老闆的名言:“業務複雜度是不會因為系統設計變化而減少的,它隻是從一個地方轉移到了另外的地方。”,我們可以知道,這種寫法其實沒有使得原來就有的判斷和循環變少。隻是改變了文法結構。
讀者可以将這種操作作為一種“文法糖”進行使用。如果是在團隊項目中,則需要尊重團隊成員的共同意見,因為這種操作并非所有人都願意接受。
當然,這種做法在一些地方會産生好處。例如在将本地函數、IEnumerable和Task相結合的 T10測試網絡連接配接 中。這種寫法就減少了傳統寫法中需要建立一個
List
或者
Array
的開銷。
總之,這種寫法,提供了一種新的思路。是否一定要使用,将取決于讀者團隊的接受程度。
異步疊代器
在 C# 8 和 .netcore 3.0 到來的版本中,我們迎接到了
IAsyncEnumerable
接口來實作異步疊代器的功能。
IEnumerable
是同步方法的疊代器,
IAsyncEnumerable
可以看做是其異步版本。有了這個接口,那麼在疊代的過程中也可以充分利用async/await帶來的程式設計快感。
本系列中沒有添加這部分的示例,但是主體思路是一緻的。
她的出現,隻會使得開發者更容易應用以上總結的幾種主要場景。
詳細的例子,可以參見相關文章進行了解。
總結
本系列到此便結束了,希望讀者多在實踐中體會以上總結的幾種使用場景。
本系列中的例子已經全部使用dotnetfiddle.net進行了重寫,讀者可以直接在本部落格的頁面上運作這些示例。
如果無法正常的展示示例,讀者也可以通過本倉庫下載下傳示例相關的代碼。