說來簡單,您只需實作整個 IEnumerable 介面或 IEnumerable(Of T) 介面。我們以MSDN中 IEnumerable 介面 範例來說明 IEnumerable 介面實作。
Imports System Imports System.Collections ''' <summary> ''' Person 類例 ''' </summary> Public Class Person Public firstName As String Public lastName As String ''' <summary> ''' 建構式 ''' </summary> ''' <param name="fName">姓</param> ''' <param name="lName">名子</param> Sub New(ByVal fName As String, ByVal lName As String) Me.firstName = fName Me.lastName = lName End Sub End Class
首先,宣告一個Class Person(個人),裡面只有兩個屬性,firstName 和 lastName,並且了一個簡單的初始化建構式。
''' <summary> ''' People 類別 ''' </summary> ''' <remarks>實作 IEnumerable</remarks> Public Class People Implements IEnumerable ' 私有 _person()陣列變數,存放 Person類別資料 Private _people() As Person ''' <summary> ''' 建構式 ''' </summary> ''' <param name="pArray">Person 陣列</param> Sub New(pArray() As Person) ' 初始化陣列物件 _people = New Person(pArray.Length - 1) {} ' 儲存至私有 _person()陣列變數 Dim i As Integer For i = 0 To pArray.Length - 1 ' 將傳入物件陣列儲存在 _people陣列 _people(i) = pArray(i) Next i End Sub ''' <summary> ''' 實作 IEnumerable.GetEnumerator 方法 ''' </summary> ''' <returns>列舉 _people()陣列的結果</returns> Function GetEnumerator() As IEnumerator _ Implements IEnumerable.GetEnumerator ' 回傳列舉 _people陣列結果 Return New PeopleEnum(_people) End Function End Class
宣告一個Class People(人),重點在第二行,它實作了 IEnumerable介面,當您輸入完 Implements IEnumerable 按下 Enter 後,會自動跳出需實作的函式,即 GetEnumerator() 函式。People類別主要是要存放 Person(個人)類別資料,存放於陣列之中,然實透過實作 GetEnumerator() 函式,讓 People類別擁有可反覆運作的能力。在 GetEnumerator() 函式中,我們還需要透過一個 PeopleEnum類別來幫忙完成最後一件事。
''' <summary> ''' 列舉 People 類別 ''' </summary> ''' <remarks>實作 IEnumerable</remarks> Class PeopleEnum Implements IEnumerator Public _people() As Person ' 在第一個列舉之前的位置 ' 直到第一次呼叫 MoveNext() Dim position As Integer = -1 ''' <summary> ''' 建構式,初始化 _people() 陣列 ''' </summary> ''' <param name="list">Person陣列</param> Sub New(list() As Person) _people = list End Sub ''' <summary> ''' 實作 MoveNext() 函式 ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Function MoveNext() As Boolean _ Implements IEnumerator.MoveNext position = position + 1 Return (position < _people.Length) End Function ''' <summary> ''' 實作 Reset() 副程式 ''' </summary> Sub Reset() Implements IEnumerator.Reset position = -1 End Sub ''' <summary> ''' 實作唯讀 Current() 屬性 ''' </summary> ''' <value></value> ''' <returns>_people陣列值</returns> ''' <remarks></remarks> Public ReadOnly Property Current() As Object _ Implements IEnumerator.Current Get Try ' 回傳現在位置的 _people陣列值 Return _people(position) Catch ex As IndexOutOfRangeException Throw New InvalidOperationException() End Try End Get End Property End Class
PeopleEnum類別,很明顯是在進行列舉用的類別。
注意實作的是 IEnumerator介面,我們必須實作此 IEnumerator介面裡的三個方法。首先是 position 變數,For Each 每次呼叫時的動作,其實都是呼叫 MoveNext() 函式,陣列由 0 開始,所以第一次呼叫的值應該是如 _people(0) 來回傳第一筆陣列值,所以我們一開始先讓 position 的值為 -1。在 MoveNext() 函式中,我們做的事很簡單,一是先進行 +1 的動作,然後判斷 +1 之後是否超出陣列大小。在 Reset() 更簡單,Reset 代表重新設定,就讓 position 回到最原頭的 -1。最後一個也是最重要的屬性,Current() 屬性,也就是回傳當前陣列的值。
最後整個完成的類別圖:
圖一:實作 IEnumerable 介面範例類別圖 |
最後執行的程式碼。
Module Module1 Sub Main() Dim peopleArray() As Person = { New Person("John", "Smith"), New Person("Jim", "Johnson"), New Person("Sue", "Rabon")} Dim peopleList As New People(peopleArray) Dim p As Person ' 注意,peopleList 可以使用 For Each 列舉 For Each p In peopleList Console.WriteLine(p.firstName + " " + p.lastName) Next Console.ReadLine() ' 結果: ' ' John Smith ' Jim Johnson ' Sue Rabon End Sub End Module
我們傳入一個 Person的陣列物件(peopleArray)給 People類別的執行個體 peopleList。 peopleList 執行個體為什麼能有列舉能力,因為 People類別有實作 IEnumerable介面。那您會說,我平常在用的 Array、ArrayList、List … 不都可以直接使用嗎?對,你去查查 MSDN,那是因為人家在這些類別裡已經幫您實作好 IEnumerable介面。我們在來看一個簡單的範例,一週的日期。
Module Module1 Sub Main() ' 參考 ArrayList 的宣告 ' Public Class ArrayList ' Implements IList, ICollection, IEnumerable, ICloneable Dim weekDayList As New ArrayList From {"Sun-星期日", "Mon-星期一", "Tue-星期二", "Wed-星期三", "Thu-星期四", "Fri-星期五", "Sat-星期六"} ' 找出 S 開頭的日期 Console.WriteLine("使用 For Each 找出 S 開頭的日期") Dim day As String = "" For Each day In weekDayList If day.StartsWith("S") Then Console.WriteLine(day.ToString()) End If Next Console.WriteLine() Console.ReadLine() Console.WriteLine("使用 IEnumerable介面來找出 T 開題的日期") ' 讓 dayEnum 擁有列舉能力 Dim dayEnum As IEnumerator = weekDayList.GetEnumerator() While dayEnum.MoveNext Dim dayString As String = dayEnum.Current.ToString() If dayString.StartsWith("T") Then Console.WriteLine(dayString) End If End While Console.WriteLine() Console.ReadLine()
' 結果
' 使用 For Each 找出 S 開頭的日期 ' Sun-星期日 ' Sat-星期六 ' ' 使用 IEnumerable介面來找出 T 開題的日期 ' Tue-星期二 ' Thu-星期四 End Sub End Module
ArrayList類別是一個已經實作 IEnumerable介面的類別,所以我們很輕易在程式中使用 For Each 來取得資料。第二段程式主要是透過 GetEnumerator() 來讓 dayEnum 有列舉能力(IEnumerator介面提供),然後透過 MoveNext 與 Current 來移動陣列與取出陣列值。
看完第一段(Person)與第二段(dayEnum)程式碼,有沒有發現,人家幫我們做了好多事。但如一開頭所言,一句「實作 IEnumerable介面」,你看看要做多少事?
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。