1:枚舉器和可枚舉類型
我們知道使用foreach可以遍歷數組中的元素。那么為什么數組可以被foreach語句處理呢,下面我們就進行討論一下這個問題。
2:使用foreach語句
我們知道當我們使用foreach語句的時候,這個語句為我們依次取出了數組中的每一個元素。
例如下面的代碼:
1 int[] arr = { 1, 2, 3, 4, 5, 6 }; 2 foreach( int arry in arr ) 3 { 4 Console.WriteLine("Array Value::{0}",arry); 5 }
輸出效果為
為什么數組可以使用foreach來遍歷,原因是數組可以按需提供一個叫做枚舉器(enumerator)的對象,枚舉器可以依次返回請求的數組中的元素,枚舉器知道項的次序並且跟蹤它在序列中的位置。依次返回請求的當前項。
對於有枚舉器的類型而言,必須有一個方法來獲取它這個類型。獲取一個對象枚舉器的方法是調用對象的GetEnumrator方法,實現GetEnumrator方法的類型叫做可枚舉類型。那么數組就是可枚舉類型。
下圖演示一下可枚舉類型和枚舉器之間的關系。
foreach結構設計用來和可枚舉類型一起使用,只要給它的遍歷對象是可枚舉類型,比如數組。
1:通過調用GetEnumrator方法獲取對象的枚舉器。
2:從枚舉器中請求每一項並且把它作為迭代器,代碼可以讀取該變量,但不可以改變
foreach(Type VarName in EnumrableObject )
{
...
}
EnumrableObjec必須是可枚舉類型。
2:IEnumrator接口
IEnumrator接口包含了3個函數成員:Current、MoveNext以及Reset;
.Current是返回序列中當前位置項的屬性。(注意:Current它是只讀屬性,它返回Object類型的引用,所以可以返回任意類型)
.MoveNext是把枚舉器位置前進到集合中下一項的方法。它也但會布爾值,指示新的位置是否是有效位置。
注:如果返回的位置是有效的,方法返回true;
如果新的位置是無效的,方法返回false;
枚舉器的原始位置在序列中的第一項之前,因此MoveNext必須在第一次使用Current之前調用。
.Reset是把位置重置為原始狀態的方法。
下面我們用圖表示一下他們之間的關系
有了集合的枚舉器,我們就可以使用MoveNext和Current成員來模仿foreach循環遍歷集合中的項,例如,我們已經知道數組是可枚舉類型,所以下面的代碼手動做foreach語句
自動做的事情。
代碼如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Collections; 7 8 namespace ConsoleApplication1 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 int[] arr = { 1, 2, 3, 4, 5, 6 }; 15 IEnumerator ie = arr.GetEnumerator(); 16 while( ie.MoveNext() ) 17 { 18 int i = (int)ie.Current; 19 Console.WriteLine("{0}", i); 20 } 21 } 22 } 23 }
程序運行的結果為
我們來用圖解釋一下代碼中的數組結構
IEnumerable接口
數組是可枚舉類型,是因為實現了IEnumerable接口的類,所以可枚舉類都是因為實現了IEnumerable接口的類。
IEnumerable接口只有一個成員——GetEnumerator()方法,它返回對象的枚舉器。
如圖所示:
下面我們舉一個使用IEnumerator和IEnumerable的例子
下面的代碼展示了一個可枚舉類的完整示例,該類叫Component(球形)。它的枚舉器類為Shape(形狀)。
代碼如下:
1 using System; 2 using System.Collections; 3 4 namespace ConsoleApplication1 5 { 6 class Shape : IEnumerator 7 { 8 string[] _Shapes; 9 int _Position = -1; 10 11 public Shape(string[] _theShapes) 12 { 13 _Shapes = new string[_theShapes.Length]; 14 for( int i = 0; i < _theShapes.Length; i++ ) 15 { 16 _Shapes[i] = _theShapes[i]; 17 } 18 } 19 20 public Object Current 21 { 22 get 23 { 24 if ( _Position == -1 ) 25 throw new InvalidOperationException(); 26 if (_Position >= _Shapes.Length) 27 throw new InvalidOperationException(); 28 return _Shapes[_Position]; 29 } 30 } 31 32 public bool MoveNext() 33 { 34 if (_Position < _Shapes.Length - 1) 35 { 36 _Position++; 37 return true; 38 } 39 else 40 return false; 41 } 42 43 public void Reset() 44 { 45 _Position = -1; 46 } 47 } 48 49 class Component : IEnumerable 50 { 51 string[] shapes = { "Circular", "spherical", "Quadrilateral", "Label" }; 52 public IEnumerator GetEnumerator() 53 { 54 return new Shape( shapes ); 55 } 56 } 57 58 class Program 59 { 60 static void Main(string[] args) 61 { 62 Component comp = new Component(); 63 foreach ( string oshape in comp ) 64 Console.WriteLine(oshape); 65 } 66 67 } 68 }
運行結果:
如果您看了本篇博客,覺得對您有所收獲,請點擊右下角的 [推薦]
如果您想轉載本博客,請注明出處
如果您對本文有意見或者建議,歡迎留言
感謝您的閱讀,請關注我的后續博客