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
Preview
Start a free Courses trial
to watch this video
All collections implement IEnumerable and it's what makes it possible to loop through a collection using foreach.
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 the previous video, we decided that
it would be nice to be able to work
0:00
with multiple collections of objects
as if they're a single collection.
0:03
We'll encapsulate this functionality
in a class named EnumerableCompositor.
0:07
This may sound like a funny name
right now, but in a moment,
0:12
you'll see why I've
decided to name it that.
0:15
We'll add a new file to our project.
0:17
Now, because this class is meant
to be reusable across any project,
0:20
I'd normally put this in
a separate class library.
0:25
But because this is just a demonstration
on how to use generics to write
0:28
collections, we'll keep all of our code
in the generics demo project for now.
0:31
We can always move it to a different
library later if we want it.
0:36
So I would just right-click on
GenericsDemo > Add > New Item.
0:40
Chang the class name to
EnumerableCompositor.
0:46
Now before we start coding this class,
0:56
let's think a bit about what we'd
like to be able to do first.
0:59
The EnumerableCompositor will
be composed of many collections.
1:02
But we'll be able to loop through
the items contained in them
1:08
as if they're one collection.
1:11
Collections that can be looped through
like this are said to be enumerable.
1:13
That's why we've named
the class EnumerableCompositor,
1:17
it's composed of enumerables.
1:20
So let's see how we'd create a new
enumerable compositor over here in Main.
1:23
Here we'd say var ec = new
1:29
EnumberableCompositor.
1:33
We'd specify the type of item we want
to store in the collection here.
1:39
In this case it's int.
1:45
And now we can list all
of the collections here.
1:47
So we'll just say list1,
list2, set1 and array1.
1:50
We'll also want to be able to
loop through all of the items
1:57
in the enumerable compositor.
2:00
So just like we had our for loops before,
2:02
we'll have an integer to keep track of
all of the odd numbers that we encounter.
2:05
So we'll say init numodd = 0.
2:10
And we'll write a foreach loop.
2:15
Say var value in and
this time we're just gonna loop
2:19
through the enumerable compositor.
2:23
And if the value is odd,
2:27
Then we will increment numOdd.
2:36
Or even better,
2:42
we'd like to be able to write this as
a single link statement like this.
2:44
We can change all of
these to just EC.count.
2:49
Notice that we have these
red squiggly lines here.
2:56
This is because we haven't actually
implemented the enumerable compositor yet.
2:59
We're just showing here what
we'd like to be able to do.
3:03
By the end of this workshop,
3:07
we'll even see how we can
make this code even simpler.
3:08
Notice that enumerable compositor
takes a generic type parameter here.
3:12
Here we're specifying that we want in
enumerable compositor to be a collection
3:17
of integers.
3:21
Let's see how to turn enumerable
compositor into a generic class.
3:23
For now, let's comment out this
code since it doesn't compile yet.
3:27
We can make enumerable compositor
a generic class by adding opening and
3:34
closing angle brackets
here after the class name.
3:38
Now we need to decide what to
name the generic type parameter.
3:43
By convention, generic parameter
start with a capital letter.
3:47
In most cases, if there's only one
parameter, the capital letter T is used.
3:51
We can have as many type
parameters as we'd like though.
3:57
It's actually very rare to
have more than three or four.
4:00
If there are two or more parameters, then
we should have more descriptive names.
4:04
They typically start
with a capital T though.
4:08
For example, the type parameter for
the key of a dictionary is named TKey.
4:11
And the type parameter for
the value is named TValue.
4:16
Because we only have a single parameter,
we'll just use T here.
4:21
This T is a placeholder for
4:26
the actual type that will be specified
when the class is instantiated.
4:29
We can now use T anywhere we need
to refer to the type of the item
4:33
contained in the collection.
4:37
The rule of T will become
more clear as we continue.
4:38
Now, we get to the part that
makes this class a collection.
4:41
All collection types in .NET
implement the I Enumerable interface.
4:45
In C#, for each loops can only be used
to loop through classes that implement
4:50
the I Enumerable interface.
4:54
We want to be able to loop through
all the items in our collection.
4:56
So, we'll need to implement
the IEnumerable interface here to.
5:00
The IEnumerable interface
is a generic interface.
5:04
Yes, interfaces can be generic too.
5:08
The type parameter of the I enumerable
interface is the type of the object
5:12
contained in the collection.
5:16
In our case, that will also be T.
5:18
So we can just type T here.
5:21
To make some room,
5:24
I'll delete all of these using
directives that we're not using.
5:25
Now we need to implement
the IEnumerable interface.
5:29
In fact, that's what this red
squiggly line is telling us.
5:33
We haven't yet implemented the interface.
5:37
So if we tried to compile this
we'd get a compilation error.
5:39
We can have Visual Studio generate the
code to implement the interface for us.
5:44
So if we hit control with our
cursor on the red squiggly area,
5:49
we'll see some options for
how to fix this compilation error.
5:56
As you can see here,
there are two options.
6:00
If I move the cursor over them,
it shows me the code it will generate.
6:03
Notice that the second option is to
implement the interface explicitly.
6:07
The names of the methods and properties
of an explicitly implemented interface
6:13
are prefixed by the name of the interface.
6:17
Those methods and
properties are only accessible.
6:23
When the object is explicitly
cast to that specific interface.
6:26
There are a number of reasons to do this,
but in our case we want the first option.
6:31
We'll talk more about explicitly
implemented interfaces in a bit, to have
6:37
the visual studio generate the code,
I'll just click, Implement interface.
6:41
If you're following along in a different
editor just pause the video here and
6:46
copy the code from my screen.
6:51
Two methods were added for
us both of them are named GetEnumerator.
6:53
One returns IEnumerator of T, and
the other just returns IEnumerator.
6:58
Also notice that the second one is an
explicitly implemented interface method.
7:05
We know that because it's
prefixed by a IEnumerable dot.
7:12
And it doesn't have an access
modifier such as public.
7:18
So what's going on here?
7:23
Well, actually,
we've just implemented two interfaces,
7:25
one for IEnumerable of T and
the other for IEnumerable.
7:30
One is generic and the other is not.
7:35
After clicking on IEnumerable of T,
7:37
we can hit Alt+F12 on the keyboard
to peek at its definition.
7:40
Here's the definition for IEnumerable of
T and here's the GetEnumerator method.
7:48
This is the one that returns
IEnumerator of T, but
7:54
this Interface also inherits from
the non-generic IEnumerable.
7:59
Which is a completely different interface.
8:05
We can peek at its definition
by clicking on it and
8:08
then hitting Alt + F12 on the keyboard.
8:12
Now we're looking at
the interface definition for
8:16
the non-generic IEnumerable.
8:18
It also specifies a method
named GetEnumerator
8:21
only this one returns
the non-generic IEnumerator.
8:25
When we implement an interface,
8:31
we must also implement any
interfaces that it inherits.
8:33
It's as if we had both IEnumerable
of T and I enumerator up here
8:37
even though these two interfaces are named
the same they're not the same interface.
8:54
They both specify that we must have
a method name to get in numerator.
8:59
However, they have different return types.
9:03
In C#, a class can't have two
methods with the same name
9:06
if they have different return types.
9:11
So we need to differentiate them.
9:13
We can do this by adding IEnumerable
dot to the GetEnumerator method
9:15
that's specified by the non-generic
IEnumerable interface.
9:19
This essentially hides this
method from users of the class.
9:24
And that's why there's no
public access modifier here.
9:28
The explicitly implemented GetEnumerator
method can still be accessed if the object
9:31
is explicitly cast to the non-generic
IEnumerable interface first.
9:36
This is only one reason to explicitly
implement an interface method.
9:42
Explicitly implementing interfaces
is actually a fairly advanced and
9:46
rare use of interfaces.
9:51
So we won't go much
more into it right now.
9:53
It just so happens that in order to
implement the IEnumerable of T interface,
9:56
you must also explicitly
implement the get numerator method
10:01
of the non-generic I numerable interface.
10:04
I've included more information about
explicit interface implementations
10:07
in the teacher's notes of this
video if you'd like to learn more.
10:11
We still need to write the code for
these methods.
10:15
But this is this far as will go
with implementing these right now.
10:17
Before we can finish writing them
we need to have some way to add and
10:21
store the items contained
in the collection.
10:25
We'll do that next.
10:27
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