引言 最近翻看了之前的學習筆記,看到foreach,記得當時老師講的時候,有點犯渾,不是很明白,這好比,上小學時,你不會乘法口訣,但是隨著時間的增長,你不自覺的都會了,也悟出個小道理,有些東西,你當時不太懂,但隨著你的閱歷和經驗的增長,有那麼一天你會恍然大悟,哦,原來是這樣。 自定義集合類 提到foreach就不得不說集合,那麼就先從自定義的集合開始吧。 復制代碼 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Wolfy.自定義集合 8 { 9 /// <summary> 10 /// 自定義集合類 11 /// </summary> 12 public class MyArrayList 13 { 14 /// <summary> 15 /// 集合的容量屬性 成倍數增加0,4,8,且只讀 16 /// </summary> 17 public int Capacity 18 { 19 get 20 { 21 return this.objArray.Length == 0 ? 0 : this.index > this.objArray.Length ? this.objArray.Length * 2 : this.objArray.Length; 22 } 23 } 24 /// <summary> 25 /// 集合實際元素個數 且只讀 26 /// </summary> 27 public int Count 28 { 29 get 30 { 31 return this.index; 32 } 33 } 34 private int index; 35 private object[] objArray; 36 public MyArrayList() 37 { 38 index = 0; 39 //初始化0長度的數組 40 this.objArray = new object[0]; 41 } 42 /// <summary> 43 /// 添加元素 44 /// </summary> 45 /// <param name="value">元素值</param> 46 public void Add(object value) 47 { 48 if (index >= this.objArray.Length) 49 { 50 object[] newArray = index == 0 ? new object[this.objArray.Length + 4] : new object[this.objArray.Length * 2]; 51 objArray.CopyTo(newArray, 0); 52 objArray = newArray; 53 objArray[index++] = value; 54 } 55 else 56 { 57 objArray[index++] = value; 58 } 59 } 60 /// <summary> 61 /// 添加數組 62 /// </summary> 63 /// <param name="objs"></param> 64 public void AddRange(object[] objs) 65 { 66 for (int i = 0; i < objs.Length; i++) 67 { 68 this.Add(objs[i]); 69 } 70 } 71 } 72 } 復制代碼 不知道自定義的集合和ArrayList是否一樣,可以簡單的測試一下。 復制代碼 1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Wolfy.自定義集合 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 ArrayList list = new ArrayList(); 15 //MyArrayList list = new MyArrayList(); 16 Console.WriteLine("count:" + list.Count); 17 Console.WriteLine("Capacity:" + list.Capacity); 18 list.Add(1); 19 list.Add(1); 20 Console.WriteLine("count:" + list.Count); 21 Console.WriteLine("Capacity:" + list.Capacity); 22 list.Add(1); 23 list.Add(1); 24 list.Add(1); 25 Console.WriteLine("count:" + list.Count); 26 Console.WriteLine("Capacity:" + list.Capacity); 27 list.Add(1); 28 list.Add(1); 29 list.Add(1); 30 list.Add(1); 31 list.Add(1); 32 list.Add(1); 33 Console.WriteLine("count:" + list.Count); 34 Console.WriteLine("Capacity:" + list.Capacity); 35 object[] arr = { 1, 2, 3, 4, 5, 6 }; 36 list.AddRange(arr); 37 Console.WriteLine("count:" + list.Count); 38 Console.WriteLine("Capacity:" + list.Capacity); 39 Console.Read(); 40 } 41 } 42 } 復制代碼 此時是.Net中的ArrayList,結果: 自定義的集合,結果: 輸出結果一樣,那麼現在用foreach遍歷,自定義集合中的元素。F6編譯,會提示錯誤。 foreach語句 其實foreach是怎樣工作的呢? 眾所周知foreach中in後面的對象應該是實現IEnumerable接口的,程序運行時本質是在調用IEnumerable的GetEnumerator函數來返回一個IEnumerator對象,foreach就是利用IEnumerator對象的Current,MoveNext和Reset成員來進行一段數據的枚舉。簡單的代碼實現如下: 1 //System.Collections下的IEnumerator 2 IEnumerator enumerator = this.objArray.GetEnumerator(); 3 while (enumerator.MoveNext()) 4 { 5 Console.WriteLine(enumerator.Current); 6 } 將這個代碼放在自定義集合中,定義一個方法GetArray(),然後測試一下 復制代碼 1 /// <summary> 2 /// 得到所有的元素 3 /// </summary> 4 public void GetArray() 5 { 6 //System.Collections下的IEnumerator 7 IEnumerator enumerator = this.objArray.GetEnumerator(); 8 while (enumerator.MoveNext()) 9 { 10 Console.Write(enumerator.Current+“,”); 11 } 12 } 復制代碼 測試結果: 你運行會發現多出很多逗號,原因是執行後,enumerator沒有被Dispose掉,而繼承IDisposable的迭代器(IEnumerator)在foreach結束後會被正確處理掉(調用Dispose方法)。 自定義集合實現IEnumerable接口 實現IEnumerable接口必須實現它裡面的成員GetEnumerator()方法: 1 public IEnumerator GetEnumerator() 2 { 3 throw new NotImplementedException(); 4 } 該方法的返回值為實現了IEnumerator接口的類的對象。那麼現在需要定義一個實現了該接口的類。 復制代碼 1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Wolfy.自定義集合 9 { 10 public class MyEnumerator : IEnumerator 11 { 12 /// <summary> 13 /// 返回當前指針指向的元素的值 14 /// </summary> 15 public object Current 16 { 17 get { throw new NotImplementedException(); } 18 } 19 /// <summary> 20 /// 將指針向前移動1位,並判斷當前位有沒有元素.指針默認在-1位置 21 /// </summary> 22 /// <returns></returns> 23 public bool MoveNext() 24 { 25 throw new NotImplementedException(); 26 } 27 /// <summary> 28 /// 重置 29 /// </summary> 30 public void Reset() 31 { 32 throw new NotImplementedException(); 33 } 34 } 35 } 復制代碼 迭代需要數組參數,在構造函數中將自定義集合中的數組傳進來,並且在MoveNext中需要判斷指針是否移動到數組的末尾,那麼需要數組的長度。 MyArrayList中GetEnumerator()方法實現 1 public IEnumerator GetEnumerator() 2 { 3 return new MyEnumerator(this.objArray, this.Count); 4 } MyEnumerator類 復制代碼 1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Wolfy.自定義集合 9 { 10 public class MyEnumerator : IEnumerator 11 { 12 /// <summary> 13 /// 指針的默認位置 14 /// </summary> 15 private int index = -1; 16 private object[] objArray; 17 /// <summary> 18 /// 數組長度 19 /// </summary> 20 private int count; 21 public MyEnumerator(object[] objArray, int count) 22 { 23 24 this.objArray = objArray; 25 this.count = count; 26 } 27 /// <summary> 28 /// 返回當前指針指向的元素的值 29 /// </summary> 30 public object Current 31 { 32 get { return this.objArray[index]; } 33 } 34 /// <summary> 35 /// 將指針向前移動1位,並判斷當前位有沒有元素.指針默認在-1位置 36 /// </summary> 37 /// <returns></returns> 38 public bool MoveNext() 39 { 40 index++;//指針首先向前移動一位 41 if (index < this.count) 42 { 43 return true; 44 } 45 else 46 { 47 return false; 48 } 49 } 50 /// <summary> 51 /// 重置 52 /// </summary> 53 public void Reset() 54 { 55 index = -1; 56 } 57 } 58 }