若是問你最經常使用的設計模式是哪一種?你可能會說單例模式,工廠模式。但根據我在項目裏的經驗,一個完整的應用,應該是迭代器模式。html
在本項中將會帶你們一塊兒進入迭代器模式下的IL代碼,看看迭代器內部是怎麼去進行循環迭代的;
以下代碼實現了for循環打印集合中的全部元素,以及foreach迭代打印集合中的全部元素。算法
static void Main(string[] args) { List<int> intList = new List<int>(); intList.Add(1); intList.Add(2); for(var i=0;i<intList.Count;i++) { Console.WriteLine("元素for遍歷打印:" + intList[i]); } foreach (var item in intList) { Console.WriteLine("元素foreach遍歷打印:" + item); } }
代碼輸出:
設計模式
能夠看到兩種打印方式效果一致;for循環任一一種語言都有,你們再熟悉不過,這裏再也不贅述,咱們來看下foreach迭代器模式的IL代碼(若是當前網頁過小,看不清,請將圖片右鍵另存打開,或者將圖片拖到瀏覽器新窗口打開);
數組
大概思路以下:List 下有個迭代器Enumerator,能夠經過List下的GetEnumerator方法得到此迭代器集合;而後經過迭代器的get_Current方法來獲取當前第一個元素。迭代器的MoveNext()方法判斷下一元素是否存在,若是存在取出循環;不存在結束迭代循環模式;最終,將迭代過程當中產生的系統非託管資源釋放;瀏覽器
迭代器代碼以下:設計
var enumerator = intList.GetEnumerator(); while (enumerator.MoveNext()) { Console.WriteLine("迭代器模式遍歷打印:" + enumerator.Current); } Console.ReadLine();
List<int> intList = new List<int>(); intList.Add(1); intList.Add(2); for(var i=0;i<intList.Count;i++) { if (intList[i] == 1) { intList.Remove(1); } } Console.WriteLine("集合中元素數量:" + intList.Count);
Console輸出
集合中元素數量:1
這說明for刪除成功code
foreach (var item in intList) { if (item==1) { intList.Remove(1); } } Console.WriteLine("集合中元素數量:" + intList.Count);
從如上拋出的異常得得知 var enumerator = intList.GetEnumerator();迭代器在循環迭代中是不容許對該迭代器進行刪除操做的。若是須要刪除操做,能夠再這個集合基礎上作linq操做;由於迭代器在循環迭代中是一個值對象的存在,不容許變動迭代器對象的內容;htm
思考對象
以下代碼也是運用了迭代器模式,爲何能刪除集合元素了?讀者自行思考哈。這也是迭代器方式下犧牲內存來刪除/修改元素的一種方法。blog
foreach (var item in dictionary.ToList()) { Debug.Log(item.Key + "," + item.Value); if (item.Key.Equals("s11")) { dictionary.Remove(item.Key); } }
List<int> intList = new List<int>(); intList.Add(1); intList.Add(2); for(var i=0;i<intList.Count;i++) { if (intList[i] == 1) { intList[i]=3; } Console.WriteLine("集合中元素遍歷:" + intList[i]); }
輸出:
集合中元素遍歷:3 集合中元素遍歷:2
從如上輸出看出,for修改爲功
直接編譯就通不過
以下程序,會去修改迭代器元素的屬性,而且在for跟foreach下都能運行成功。
class Program { static void Main(string[] args) { List<protocol> protocols = new List<protocol>(); var p1 = new protocol(); p1.bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; var p2 = new protocol(); p2.bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; protocols.Add(p1); protocols.Add(p2); foreach (var item in protocols) { item.bytes = p2.bytes; item.intList.Add(1); } for (var i=0;i<protocols.Count;i++) { protocols[i].bytes = p1.bytes; protocols[i].intList.Add(1); protocols[i] = p1; } Console.WriteLine("程序運行成功"); Console.ReadLine(); } } public class protocol { public byte[] bytes= { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; public List<int> intList=new List<int>(); }
既然,for效率更高,foreach效率不及for。for能作的事foreach不能作(修改刪除元素)。是否是沒有foreach的用武之地了呢,大錯特錯了,偏偏相反,每一個項目裏用的最多的反而是foreach迭代器模式,我統計了下超過工廠模式跟單例模式,不信你本身去數foreach的數量。可是在遍歷散列集合時,如字典,for就會失效了,由於下標不是有序數值了,而是看上去無序的內部散列算法。這時foreach遍歷字典就頗有用,他定義了一個枚舉器(迭代器),而這個枚舉器統一了,getCurrent(), moveNext()等用於迭代的方法;
foreach (var item in dictionary.ToList()) { Debug.Log(item.Key + "," + item.Value); if (item.Key.Equals("s11")) { dictionary.Remove(item.Key); } }
像上面的用for,for循環的i與字典的key(自定義,通常是string類型)是沒辦法創建映射關係的;因此沒法用for循環
版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。 本文連接:http://www.javashuo.com/article/p-odyaqksf-nv.html