This workshop will be retired on May 1, 2025.
Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Well done!
You have completed Creating Data Structures Using C# Generics!
You have completed Creating Data Structures Using C# Generics!
Preview
Foreach loops use enumerators (AKA iterators) to loop through a collection. The magical yield keyword makes it easy to create enumerators.
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
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 upYou need to sign up for Treehouse in order to set up Workspace
Sign up