End Function Public Sub Reset() _ Implements IEnumerator。Reset _currNode = _firstNode End Sub End Class A class that can be enumerated must fulfill two objectives: implement the IEnumerable interface and implement the IEnumerator interface。 The IEnumerable class has a single method; GetEnumerator(); which is used to retrieve a class instance that implements the IEnumerator interface。 The two interfaces are split because retrieving the iteration functionality and iter ating the collection are two separate steps。 However; in the case of LinkedListEnumerable; these steps are bined into one class; and that is often the case。 The best way to explain how LinkedListEnumerable works is to go through the code and explain what methods and properties are called。 1。 The code in the client application starts a For Each loop; and sets up a context where a collection of elements is being iterated。 2。 The code calls the collection iterator。 In the example; this means calling the method RoomGroupingIterator()。 3。 RoomGroupingIterator() returns an instance of LinkedListEnumerable; which is assigned the linked list that will be iterated。 Public Function RoomGroupingIterator() As IEnumerable Return New LinkedListEnumerable(_roomGroupings) End Function …………………………………………………………Page 241…………………………………………………………… C H AP TE R 8 ■ L E AR N IN G AB O U T CO M P O N E N T O R IE N TE D A R CH I TE C TU R E 219 4。 The method LinkedListEnumerable。GetEnumerator() is called; and an instance of IEnumerator is returned。 5。 The code calls the method LinkedListEnumerable。MoveNext()。 6。 The implementation of MoveNext() returns True to indicate that it was possible to move to the next element。 If False is returned; it means that the end of the collection—or in this case; the linked list—is reached。 7。 If MoveNext() returns True; then the property LinkedListEnumerable。Current() is called to retrieve the current linked list element。 8。 The retrieved linked list element is assigned to the variable of the For Each loop; which is rg in this example。 9。 Control is returned to the For Each loop; and the user code does something with the linked list element。 10。 When the For Each loop attempts another iteration; steps 5 through 9 are repeated until MoveNext() returns False。 11。 When MoveNext() returns False; the iterator exits; causing an exit of the For Each loop。 Adding Rooms to Groupings The data handle that we defined when adding the grouping is used when we add a room to a grouping。 The idea of the handle is to provide a reference that the kernel can use。 Since the handle is an instance of a RoomGrouping type; whenever a room is added to a grouping based on a handle; it is not necessary to find the room grouping。 The handle is the room grouping; and all that is necessary is a type cast。 The following demonstrates how to add a room to a room grouping (in LightingController)。 Public Sub AddRoomToGrouping(ByVal grouping As Object; ByVal room As IRoom) Dim roomGrouping As RoomGrouping = TryCast(grouping; RoomGrouping) If roomGrouping Is Nothing Then Throw New Exception( _ 〃Handle grouping is not a valid room grouping instance〃) End If Dim oldRooms As Room = TryCast(roomGrouping。Rooms; Room) If oldRooms Is Nothing Then roomGrouping。Rooms = New Room() With {。ObjRoom = room} Else roomGrouping。Rooms。Insert(New Room() With {。ObjRoom = room}) End If End Sub In the implementation of AddRoomToGrouping(); the first step is to cast the handle grouping to an instance of RoomGrouping。 The cast used is the TryCast() function; so that if the cast fails; it is only necessary to test if roomGrouping is not Nothing。 Executing the Nothing test is absolutely vital; otherwise; you might perform operations that will cause an exception to be thrown。 …………………………………………………………Page 242…………………………………………………………… 220 CH AP T E R 8 ■ L E A R N IN G AB OU T CO M P O N E N TO R IE N T E D AR C HI TE CT U R E Once the handle has been cast to a RoomGrouping instance; adding a room to the linked list is trivial。 Adding a room involves only assigning the head of the list if there are no rooms in the list; or calling the method Insert() if there are rooms。 Performing Operations on a Group With a grouping defined; you can perform global operations that affect all rooms of a grouping。 One example is turning off the lights in all the rooms in a grouping; which is based on the IRoom interface instance。 Here is the code to turn off all of the lights in a grouping: Public Sub TurnOffLights(ByVal grouping As Object) Dim enumerableGrouping As LinkedListEnumerable = _ New LinkedListEnumerable(TryCast(grouping; BaseLinkedListItem)) For Each room As IRoom In enumerableGrouping Dim remote As IRemoteControlRoom = TryCast(room; IRemoteControlRoom) Dim sensorRoom As ISensorRoom = TryCast(room; ISensorRoom) If sensorRoom IsNot Nothing Then If Not sensorRoom。IsPersonInRoom Then Continue For End If ElseIf remote Is