Click here to Skip to main content
Click here to Skip to main content

A Beginner's Tutorial on Implementing IEnumerable Interface and Understanding yield Keyword

By , 11 Oct 2012
 

Introduction

In this article we will discuss about the IEnumerable interface. We will discuss how IEnumerable interface facilitate the use of foreach statement to iterate through a set of data. We will then look how to implement our own collections that implement IEnumerable interface. The use of yield keyword and Enumerating generic collections will also be discussed in this article.

Background 

Whenever we work with collection of objects, we might find ourselves in need to iterate the collection. The best way to iterate through a collection is by implementing the Iterator pattern. (refer: Understanding and Implementing the Iterator Pattern in C# and C++[^]). C# provides a very clean construct of foreach statement to iterate in a read only manner over a collection.

C# also provides us the possibility of using the same foreach construct and all the enumeration techniques on our custom collection objects by implementing the IEnumerable interface. So let us see how we can implement IEnumerable interface with our custom collection classes.

Using the code

Enumerating the Collection classes

Before starting the discussion let us see how we can use the Built-in classes and iterate over them. Lets start by looking into the ArrayList class that implements IEnumerable and see how we can have read only iteration over that using foreach statement. 

// Let us first see how we can enumerate an object implementing IEnumerable
ArrayList list = new ArrayList();

list.Add("1");
list.Add(2);
list.Add("3");
list.Add('4');

foreach (object s in list)
{
    Console.WriteLine(s);
}

Enumerating the Generic Collection classes

The Arraylist class is a generalized class that let us keep a collection. We can also have a generic class in which we can provide the type along with the data. Iterating over generic collection classes is also possible because they implement IEnumerable<T> interface. Lets see how we can enumerate over a generic collection.

// Let us first see how we can enumerate an object implementing IEnumerable<T>
List<string> listOfStrings = new List<string>();

listOfStrings.Add("one");
listOfStrings.Add("two");
listOfStrings.Add("three");
listOfStrings.Add("four");

foreach (string s in listOfStrings)
{
    Console.WriteLine(s);
}

Now our objective is to have our own custom collection class and a generic collection class that should implement the IEnumerable and IEnumerable<T> interface respectively to provide the possibility of enumerating over them.

Understanding the yield keyword

Before jumping into the Implementation of these classes, we need to understand a very important keyword yield which actually facilitate the enumeration over collection. yield statement is used while returning a value from a function.

A normal method call like the one shown below will return only the first value no matter how many times it is called.

static int SimpleReturn()
{
    return 1;
    return 2;
    return 3;
}

static void Main(string[] args)
{
    // Lets see how simeple return works
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
}

The reason for this is that the normal return statement does not preserve the state of the function while returning. i.e. every call to this function is a new call and it will return the first value only.

Where as if I replace the return keyword by yield return then the function will become capable of saving its state while returning the value. i.e. when the function is called second time, it will continue the processing from where is has returned in the previous call.

static IEnumerable<int> YieldReturn()
{
    yield return 1;
    yield return 2;
    yield return 3;
}
static void Main(string[] args)
{
    // Lets see how yield return works
    foreach (int i in YieldReturn())
    {
        Console.WriteLine(i);
    }
}

When we run the above code it will return 1,2 and then 3. The only catch while using the yield return statement is that the function should return an IEnumerable and should be called from an iteration block i.e. foreach statement.

Implementing IEnumerable in our custom Collection class

Now in our custom collection classes, if we define a function that will iterate over all the elements in the collection and return then using the yield keyword, we will be able to get hold of all the elements in the the collection.

So let us define our own MyArrayList class and implement IEnumerable interface, which will force us to implement the GetEnumerator function. This function will iterate over the collection and do a yield return on all the elements.

class MyArrayList : IEnumerable
{
    object[] m_Items = null;
    int freeIndex = 0;

    public MyArrayList()
    {
        // For the sake of simplicity lets keep them as arrays
        // ideally it should be link list
        m_Items = new object[100];
    }

    public void Add(object item)
    {
        // Let us only worry about adding the item 
        m_Items[freeIndex] = item;
        freeIndex++;
    }

    // IEnumerable Member
    public IEnumerator GetEnumerator()
    {
        foreach (object o in m_Items)
        {
            // Lets check for end of list (its bad code since we used arrays)
            if(o == null)
            {
                break;
            }

            // Return the current element and then on next function call 
            // resume from next element rather than starting all over again;
            yield return o;
        }
    }
}

This class will now let us enumerate all the elements using a foreach stemement.

static void Main(string[] args)
{
    //Let us now go ahead and use our custom MyArrayList with IEnumerable implemented
    MyArrayList myList = new MyArrayList();

    myList.Add("1");
    myList.Add(2);
    myList.Add("3");
    myList.Add('4');

    foreach (object s in myList)
    {
        Console.WriteLine(s);
    }
}

Note: This class is neither complete not a very good implementation. The only purpose of the sample implementation is to demonstrate the implementation of IEnumerable interface.

Implementing IEnumerable<T> in our custom Generic Collection class

Let us now take this approach a little further and define a generic collection class capable of being enumerated. To do this we need to implement IEnumerable<T> interface. 

class MyList<T> : IEnumerable<T>
{
    T[] m_Items = null;
    int freeIndex = 0;

    public MyList()
    {
        // For the sake of simplicity lets keep them as arrays
        // ideally it should be link list
        m_Items = new T[100];
    }

    public void Add(T item)
    {
        // Let us only worry about adding the item 
        m_Items[freeIndex] = item;
        freeIndex++;
    }

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        foreach (T t in m_Items)
        {
            // Lets check for end of list (its bad code since we used arrays)
            if (t == null) // this wont work is T is not a nullable type
            {
                break;
            }

            // Return the current element and then on next function call 
            // resume from next element rather than starting all over again;
            yield return t;
        }
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        // Lets call the generic version here
        return this.GetEnumerator();
    }

    #endregion
}

This class will now let us enumrate all the elements using a foreach stemement.

static void Main(string[] args)
{
    // Let us first see how we can enumerate an custom MyList<t> class implementing IEnumerable<T>
    MyList<string> myListOfStrings = new MyList<string>();

    myListOfStrings.Add("one");
    myListOfStrings.Add("two");
    myListOfStrings.Add("three");
    myListOfStrings.Add("four");

    foreach (string s in myListOfStrings)
    {
        Console.WriteLine(s);
    }
}
</t>

So now we have a collection class and a generic collectio class that implement IEnumerable and IEnumerable<T> respectively. Althogh These class is neither complete not a very good implementation but they do serve the purpose of the article i.e. to demonstrate the implementation of IEnumerable interface.

Point of interest

What we have tried to do in this article is see how can we implement the IEnumerable and IEnumberable<T> interface. We have looked into the significance of yield keyword. This stuff is known to most experienced C# programmers but the beginners might find it useful. I hope this has been informative.

History

  • 11 October 2012: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Rahul Rajat Singh
Software Developer (Senior)
India India
Member
I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems.
 
Some CodeProject Achievements:
  • 9th in Best Web Dev article of March 2013
  • 7th in Best Web Dev article of January 2013
  • 2nd in Best C# article of December 2012
  • 5th in Best overall article of December 2012
  • 5th in Best C# article of October 2012
  • 4th in Best Web Dev article of September 2012
  • 3rd in Best C# article of August 2012
  • 5th in Best Web Dev article of August 2012
  • 5th in Best Web Dev article of July 2012
  • 3rd in Best Overall article of June 2012
  • 2nd in Best Web Dev article of June 2012
  • 5th in Best Web Dev article of May 2012
  • 6th in Best Web Dev article of April 2012
  • 4th in Best C++ article of April 2012
  • 5th in Best C++ article of March 2012
  • 7th in Best Web Dev article of March 2012
  • 5th in Best Web Dev article of February 2012
  • 7th in Best Web Dev article of February 2012
  • 9th in Best Web Dev article of February 2012
  • 5th in Best C++ article of February 2012

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberJe717 May '13 - 22:13 
Very useful article.
GeneralMy vote of 5memberbestdealex1 May '13 - 8:48 
A very good read to get a general feeling of IEnumerable. Also a good starting point for learning yield
GeneralMy vote of 4memberPeter Traegaadh14 Apr '13 - 21:39 
A no nonsense description, only using the code necessary to explain, resisting the temptation to decorate the code with a complete implementation that only would clutter the code.
QuestionSimilar example in Trey Nash's book has typomembercharles4816 Mar '13 - 16:21 
Thanks Rahul.
 
On page 241 of Trey Nash's "Accelerated C# 2008", he has a similar example, but instead of
 
System.Collections.IEnumerator  System.Collections.IEnumerable.GetEnumerator()
 
He has just
 
IEnumerator IEnumerable.GetEnumerator()
 
which does not compile in VS2008.
AnswerRe: Similar example in Trey Nash's book has typoprofessionalDylan Roy13 May '13 - 7:50 
What if you leverage a using statement?
using System.Collections;
...
IEnumerator IEnumerable.GetEnumerator();

QuestionNumber 1memberiwitass9 Mar '13 - 0:41 
I had problem understanding the implementation of IEnumerable interface but this article was so simple an to the point that now i understand everything except why do we add:
 
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
// Lets call the generic version here
return this.GetEnumerator();
}
 
at the bottom what is its purpose?
Generalthank youmemberARUN MENON6 Mar '13 - 1:11 
thank you rahul..nice article for a beginner...
GeneralMy vote of 5memberwangxj_nemo17 Jan '13 - 23:01 
Very Nice,it's good for beginner,i like it,thanks,please go on...
GeneralMy vote of 5membermayankgupta68819 Nov '12 - 1:10 
Easy and Good Explanation
GeneralMy vote of 5memberMihai MOGA18 Nov '12 - 7:34 
This is a great inspiring article. I am pretty much pleased with your good work. You put really very helpful information. Keep it up once again.
GeneralMy vote of 3memberOshtri Deka7 Nov '12 - 22:50 
I've expected better example.
GeneralMy vote of 5memberSavalia Manoj M6 Nov '12 - 17:21 
Good one
QuestionnicememberCIDev22 Oct '12 - 9:11 
A clearly written article with useful information. Although, I would like to see some more in-depth coverage of the topic, it is still a decent article.
Just because the code works, it doesn't mean that it is good code.

GeneralMy vote of 4memberRaffyTheAlmighty22 Oct '12 - 4:01 
I’m a beginner on C# and .Net and this article certainly contributed to my learning (specifically about the Yield keyword). Keep up the good work.
GeneralMy vote of 4memberAbdelhamid Derrar20 Oct '12 - 3:44 
nice article
QuestionMy vote of 3memberFlorin Bombeanu16 Oct '12 - 2:03 
Would have been more interesting to see some differences between ienumerable and ienumerator.
yield was interesting though.
QuestionGood job... My vote of 4... few suggestions...memberMember 267485015 Oct '12 - 0:10 
Hi,
 
I like your article. You can improve it further by adding answer to some doubts which may occur in reader's mind like Why the function should return an IEnumerable and should be called from an iteration block i.e. foreach statement.
 
In the example the function using yield is returning IEnumerator, raising a doubt again, is IEnumerator and IEnumerable same?
 
public IEnumerator GetEnumerator()
 
I am sure such improvement will get you a 5/5 Smile | :)
QuestionMy vote of 5 - sorry about the wingersmemberPetr Kohout12 Oct '12 - 12:49 
Great article. I have really strugged with this concept and your article was like turning on a lamp in a dark room...aha! now I see it, now I get it.
 
I am sick of people sitting in judgement...snug bastards. For each comment of less than 3 I challenge the writer to have the balls of acutally doing better..but alas no all they do is sit back and complain... grow up guys.
 
Cheers
GeneralMy vote of 2membercjb11011 Oct '12 - 20:46 
If you'd gone further, and ended with a more detailed example (esp without 'this is bad' comment in the code), otherwise this is just the same as MSDN.
GeneralMy vote of 3memberKlaus Luedenscheidt11 Oct '12 - 17:38 
There are so much beginner examples on this topic in the web. Your article doesn't show much more than the MSDN help. I would appreciate if you had shown a more complex real world example.
GeneralMy vote of 2memberNick Hounsome11 Oct '12 - 4:53 
Surely if you are going to go to the trouble of writing this article you can come up with a better example. Also your demo of MyList is poor as it would work just as the same with IEnumerable as IEnumerable
GeneralMy vote of 5memberDrABELL11 Oct '12 - 3:25 
Excellent article from both practical and didactic perspectives, 5*!
GeneralMy vote of 5memberSanjay K. Gupta11 Oct '12 - 2:35 
Simple and Nice Example of yield. Thanks for sharing.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 11 Oct 2012
Article Copyright 2012 by Rahul Rajat Singh
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid