Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#

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

Rate me:
Please Sign up or sign in to vote.
4.82/5 (121 votes)
11 Oct 2012CPOL4 min read 510.1K   1.8K   147   49
This article discusses how to implement IEnumerable interface and using yield keyword.

Introduction

In this article, we will discuss about the IEnumerable interface. We will discuss how IEnumerable interface facilitates the use of foreach statement to iterate through a set of data. We will then look at 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. Let's start by looking into the ArrayList class that implements IEnumerable and see how we can have read only iteration over that using foreach statement.

C#
// 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 lets 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. Let's see how we can enumerate over a generic collection.

C#
// 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 facilitates 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.

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

static void Main(string[] args)
{
    // Let's see how simple 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.

Whereas, 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 a second time, it will continue the processing from where it has returned in the previous call.

C#
static IEnumerable<int> YieldReturn()
{
    yield return 1;
    yield return 2;
    yield return 3;
}
static void Main(string[] args)
{
    // Let's 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 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.

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

    public MyArrayList()
    {
        // For the sake of simplicity, let's 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)
        {
            // Let's check for end of list (it's 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.

C#
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 nor 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.

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

    public MyList()
    {
        // For the sake of simplicity, let's 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)
        {
            // Let's check for end of list (it's bad code since we used arrays)
            if (t == null) // this won't work if 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()
    {
        // Let's call the generic version here
        return this.GetEnumerator();
    }

    #endregion
}

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

C#
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);
    }
}

So now we have a collection class and a generic collection class that implement IEnumerable and IEnumerable<T> respectively. Although these classes are neither complete nor a very good implementation, 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 beginners might find it useful. I hope this has been informative.

History

  • 11th October, 2012: First version

License

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


Written By
Architect
India India

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. IMO, C# is the best programming language and I love working with C# and other Microsoft Technologies.

  • Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development with Microsoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com[^]

  • Microsoft MVP 2015

Comments and Discussions

 
GeneralMy vote of 5 Pin
tal_segal28-Nov-22 23:02
tal_segal28-Nov-22 23:02 
GeneralMy vote of 5 Pin
tal_segal28-Nov-22 23:01
tal_segal28-Nov-22 23:01 
QuestionThanks Pin
Sebastian Sánchez18-Jul-18 16:49
Sebastian Sánchez18-Jul-18 16:49 
QuestionMy vote 5 Pin
MassimoPallara2-Feb-18 5:12
MassimoPallara2-Feb-18 5:12 
SuggestionA little bit confusing Pin
setezerocinco 28-May-17 22:46
setezerocinco 28-May-17 22:46 
QuestionThanks Pin
awesomeAkki27-Mar-17 6:19
awesomeAkki27-Mar-17 6:19 
Praisethanks! Pin
Member 1275199221-Sep-16 3:04
Member 1275199221-Sep-16 3:04 
QuestionSuper !!!!! Pin
Bogdan71f4-Aug-16 21:30
Bogdan71f4-Aug-16 21:30 
GeneralMy vote of 5 Pin
Akhil Mittal14-Jul-15 21:06
professionalAkhil Mittal14-Jul-15 21:06 
Good one. There is one Shiv Prasad Koirala video on this too.
GeneralMy vote of 5 Pin
Suffyan Asad29-Dec-14 8:58
Suffyan Asad29-Dec-14 8:58 
GeneralYield Versus Implementing Enumerator Pin
Edward Rowe4-Nov-14 4:23
Edward Rowe4-Nov-14 4:23 
GeneralRe: Yield Versus Implementing Enumerator Pin
Kent K28-Dec-14 19:23
professionalKent K28-Dec-14 19:23 
GeneralMy vote of 1 Pin
Member 1109651820-Sep-14 0:16
Member 1109651820-Sep-14 0:16 
QuestionVery wrong Pin
Musketir6-Jun-14 0:10
Musketir6-Jun-14 0:10 
AnswerRe: Very wrong Pin
Edward Rowe4-Nov-14 4:28
Edward Rowe4-Nov-14 4:28 
AnswerRe: Very wrong Pin
PaperTape5-Mar-16 7:41
professionalPaperTape5-Mar-16 7:41 
GeneralRe: Very wrong Pin
tal_segal28-Nov-22 23:44
tal_segal28-Nov-22 23:44 
GeneralMy vote of 5 Pin
Dexterslabaratory9-Apr-14 6:25
Dexterslabaratory9-Apr-14 6:25 
GeneralMy vote of 5 Pin
usrikanthvarma6-Aug-13 6:10
usrikanthvarma6-Aug-13 6:10 
GeneralMy vote of 5 Pin
karthik cad/cam29-Jul-13 1:34
karthik cad/cam29-Jul-13 1:34 
GeneralMy vote of 5 Pin
hc.baird@gmail.com10-Jul-13 0:33
hc.baird@gmail.com10-Jul-13 0:33 
GeneralMy vote of 4 Pin
chandanpatil20-Jun-13 21:14
chandanpatil20-Jun-13 21:14 
QuestionPlease explain what yield is doing here. Pin
Ravi_Raturi29-May-13 2:03
Ravi_Raturi29-May-13 2:03 
AnswerRe: Please explain what yield is doing here. Pin
Corey Murtagh5-Aug-13 15:48
Corey Murtagh5-Aug-13 15:48 
GeneralMy vote of 5 Pin
Je717-May-13 22:13
Je717-May-13 22:13 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.