Enumerators6:10 with Jeremy McLain
Foreach loops use enumerators (AKA iterators) to loop through a collection. The magical yield keyword makes it easy to create enumerators.
In order to allow looping through all the items contained in the collections, 0:00 we need to finish implementing these GetEnumerator methods. 0:04 Foreach loops use these methods to get an enumerator object which 0:07 it in turn uses to access the items in the collection. 0:11 Let's take a quick look at the IEnumerator interface by clicking on it and 0:15 then hitting Alt+F12. 0:20 IEnumerator <T> provides a property named Current. 0:24 This contains the current object in the foreach loop. 0:28 Notice that IEnumerator <T> inherits from IEnumerator. 0:32 Let's see what that looks like by hitting Alt+F12 to peek at it. 0:37 It also has a property named Current but 0:41 it adds two methods named MoveNext and Reset. 0:44 MoveNext makes it so that Current now refers to the next item in the collection. 0:50 It returns false if it's reached the end of the collection. 0:56 Reset resets the enumerator so 0:59 that it starts at the beginning of the collection again. 1:01 So there you go, there's no magic here. 1:04 A foreach loop is just syntactic sugar that's calling these methods and 1:07 properties on an enumerator object. 1:11 Now all we need to do is construct an enumerator and 1:14 return it from the GetEnumerator method. 1:17 We could implement the IEnumerator interface and handle this ourselves. 1:21 But C# provides a construct that generates an enumerator for 1:26 us when the code is compiled. 1:30 To take advantage of this feature of C#, we need to use the yield keyword. 1:32 The first time that you see the yield keyword, 1:38 it can look like it's performing some sort of magic. 1:40 But let me show you how it works. 1:43 Let's start with the GetEnumerator method that returns IEnumerator<T>. 1:45 In here we'll just write a normal loop 1:52 that we'd use to loop through all of the items in the collections. 1:55 So I'll say foreach(var collection in _collections). 1:58 And have another loop foreach(var item in collection) 2:06 Now here's where we use the yield keyword. 2:15 We'll say yield return item; 2:19 By typing yield return item here, we're telling C# we want it to 2:25 create a special enumerator object out of the body of this method. 2:30 The special thing about this enumerator object 2:35 is that each time MoveNext is called, 2:38 the body of this method will be executed until it gets to a yield return statement. 2:41 It will then set the current property 2:45 of the enumerator to the item returned by the yield return statement. 2:48 The GetEnumerator method is then paused until the next time MoveNext is called. 2:53 When MoveNext is called again the loop continues 2:58 right after the yield return statement. 3:02 The next item is returned and then it pauses again. 3:04 This continues until the end of the GetEnumerator method is reached. 3:08 At which point all of the items will have been returned and 3:12 MoveNext will return false. 3:16 This tells the foreach loop that it's reached the end of the collection. 3:18 Using yield to turn the body of a method into an enumerator is probably 3:22 the most magical feature of C#. 3:27 You don't have to understand exactly how it does this, 3:29 you only need to know that it works. 3:32 To demonstrate this working in action, I'll put some break points in the code and 3:35 we'll watch it with the debugger. 3:39 So I'll place a break point at the beginning of the GetEnumerator method 3:41 right here. 3:44 And also one here at the yield return statement. 3:46 Now over in main, let's uncomment this loop. 3:50 And I'll place a breakpoint at the beginning of it. 3:56 Now I'll hit F5 to run the debugger. 3:59 I'll open the Autos pane to see the local variables. 4:04 I'll continue to hit F5 as we loop through each item in the collection. 4:14 So here we are at the first item in the first collection. 4:22 I'll hit F5 again and we go back to the old return statement. 4:26 Now we're in the second item and so on. 4:32 See how the execution bounces back between the foreach loop inside of main and 4:35 where the yield return statement is inside of GetEnumerator. 4:40 As you can see, 4:48 every time the foreach loop moves to the next item in the collection, 4:49 the GetEnumerator method continues executing where it previously left off. 4:53 Pretty nifty. 4:58 That's all we need to do for this getEnumerator method. 5:10 But we still haven't implemented the other getEnumerator method. 5:13 Remember, this method is only called when EnumerableCompositor is first cast 5:17 to the non-generic IEnumerable interface. 5:22 It returns IEnumerator. 5:26 The GetEnumerator method up here returns IEnumerator<T> which 5:29 inherits from IEnumerator. 5:33 So for this method, all we need to do is return 5:36 whatever calling the GetEnumerator method up here returns. 5:39 So we just say return GetEnumerator. 5:44 You may have noticed that this second GetEnumerator method 5:49 was never called by the foreach loop. 5:53 It seems redundant to have this second method. 5:55 It's actually a holdover from the earlier days of C# where it 5:58 didn't have generic interfaces. 6:02 It's implemented the same way every time 6:04 by just returning whatever the other method returns. 6:07
You need to sign up for Treehouse in order to download course files.Sign up