IEnumerable in C# – A Simplified Beginners Guide

In C# and .NET, as programmers we have access to an interface that is called IEnumerable (or IEnumerable<T> for the generic version). Using IEnumerable allows us to iterate from a collection or data source by moving one element at a time. It’s also important to note that all collection types in C# inherit from IEnumerable so collections you are familiar with like arrays and lists implement IEnumerable. I have been trying to help educate around IEnumerable usage for many years now so this is a renewed effort to help get more junior developers to understand how they work.

As a bonus, if you’re interested in working with the code that you see in this article you can clone it down from GitHub by visiting this link.


A Companion Video on CSharp IEnumerable

As you read through this article on C# IEnumerables, you may find this video valuable!

YouTube player

Simple CSharp IEnumerable Example

Let’s consider the following code example that will create an array of five integers. In order to prove that an array is assignable to an IEnumerable, let’s explicitly use the “as” operator so that we can tell the compiler that we want to do this conversion. If you’re in Visual Studio and you try this, you’ll notice that the Intellisense suggestions will tell you that the as IEnumerable<int> code is actually unnecessary because it knows how to implicitly convert an array to an IEnumerable.

int[] myArray = new int[] { 1, 2, 3, 4, 5 };
IEnumerable<int> myArrayAsEnumerable = myArray as IEnumerable<int>;

Console.WriteLine("Using foreach on the array...");
foreach (var item in myArray)
{
    Console.WriteLine(item);
}

Console.WriteLine("Using foreach on the enumerable...");
foreach (var item in myArrayAsEnumerable)
{
    Console.WriteLine(item);
}

Because a CSharp IEnumerable allows us to iterate over a collection, it’s important to note that we can use a foreach loop but we cannot use a traditional counting for loop with a numeric indexer. This is because IEnumerable does not have an indexer property to retrieve elements from a particular spot in the collection.

Let’s have a look at the following code that demonstrates this:

Console.WriteLine("Using for loop on the array...");
for (int i = 0; i < myArray.Length; i++)
{
    Console.WriteLine(myArray[i]);
}

// This will not work!
//for (int i = 0; i < myArrayAsEnumerable.Length; i++)
//{
//    Console.WriteLine(myArrayAsEnumerable[i]);
//}

Are Lists Also IEnumerable in CSharp?

Yes! As mentioned at the start of this article, all collection types in C# will implement this IEnumerable interface that allow us to iterate over them.

Here’s a quick example that demonstrates nearly the exact same as what we saw prior, but this time with a List (and a different set of numbers):

List<int> myList = new List<int> { 6, 7, 8, 9, 10 };
IEnumerable<int> myListAsEnumerable = myList as IEnumerable<int>;

Console.WriteLine("Using foreach on the list...");
foreach (var item in myList)
{
    Console.WriteLine(item);
}

Console.WriteLine("Using foreach on the list enumerable...");
foreach (var item in myListAsEnumerable)
{
    Console.WriteLine(item);
}

Feel free to try this out in your code editor with other collections examples from C#! Try something like a dictionary! How does the IEnumerable interface work for something like a dictionary when you try it in your own code?


CSharp IEnumerables Are Read-Only But….

An important note is that the IEnumerable interface itself is designed to give read-only access to the user of the data. This is because we can only iterate over it. However, let’s go make a small tweak to an earlier example from this article to see something interesting that you’ll want to keep in mind.

int[] myArray = new int[] { 1, 2, 3, 4, 5 };
IEnumerable<int> myArrayAsEnumerable = myArray as IEnumerable<int>;

Console.WriteLine("Using foreach on the array...");
foreach (var item in myArray)
{
    Console.WriteLine(item);
}

// Here is the change we're making!!
Console.WriteLine("Changing first item in the array to 123");
myArray[0] = 123;

Console.WriteLine("Using foreach on the enumerable...");
foreach (var item in myArrayAsEnumerable)
{
    Console.WriteLine(item);
}

If you run the code above, what will happen? It looks like our second print out of numbers is modified to include the 123 at the start instead of 1!

So it’s true that the IEnumerable interface forces us to have read-only access. However, for newer programmers it’s a common mistake to assume that:

  1. The variable assignment of the array to another enumerable variable is a copy. It is in fact *not* a copy of the array, it is simply another variable that points to the same reference of the original array.
  2. Because IEnumerable gives read-only access, it can never change. This is also in fact false as demonstrated by the example above. Your access to the underlying data through your IEnumerable is read-only (unless you cast back to the collection), but this does not mean that someone else cannot be modifying the collection like we see in this example.

While these aren’t the most interesting aspects about enumerables, I wanted to make sure that they were called out under the assumption that you’re reading this as a more junior developer in C#.


CSharp IEnumerable Return Types For Functions

We can of course return an IEnumerable interface from functions just like we could any other collection. And there’s a special reason that I wanted to introduce this to you, the reader, towards the end of this article… But let’s keep going!

Let’s check a quick example of how we can return an Array of strings and a List of strings from a function when we mark the return type to be IEnumerable:

IEnumerable<string> FunctionThatReturnsAnArrayAsEnumerable()
{
    return new string[] { "A", "B", "C" };
}

IEnumerable<string> FunctionThatReturnsAListAsEnumerable()
{
    return new List<string> { "A", "B", "C" };
}

// we can use foreach
Console.WriteLine("Using foreach on the array function...");
foreach (var item in FunctionThatReturnsAnArrayAsEnumerable())
{
    Console.WriteLine(item);
}

Console.WriteLine("Using foreach on the list function...");
foreach (var item in FunctionThatReturnsAListAsEnumerable())
{
    Console.WriteLine(item);
}

The above example might not look too surprising based on some of the first code snippets we looked at and in this particular case, we are just down-casting the collections so that the callers of the functions have less access to the underlying collections. While there may be many reasons for wanting to do this, this opens up some doors for a more advanced topic where we can start to look at something called an “iterator” for C# and the enumerables that you are starting to use!


Summarizing IEnumerable in C#

The IEnumerable interface allows us to have a read-only view of a source of data that only allows us to sequentially iterate over it. While this seems like it might be limiting compared to some of the characteristics we get even from Arrays and Lists, there are many reasons why writing code that works on enumerables can be very beneficial. This goal of this article was to provide a simple understanding for beginners on how enumerables operate and their relationship with other collections in C#.

Perhaps it’s time now to move onto Iterators! Remember to check out my courses! If you’re interested in more learning opportunities, subscribe to my free weekly newsletter and check out my YouTube channel!

Affiliations:

These are products & services that I trust, use, and love. I get a kickback if you decide to use my links. There’s no pressure, but I only promote things that I like to use!

      • RackNerd: Cheap VPS hosting options that I love for low-resource usage!
      • Contabo: Alternative VPS hosting options with very affordable prices!
      • ConvertKit: This is the platform that I use for my newsletter!
      • SparkLoop: This service helps me add different value to my newsletter!
      • Opus Clip: This is what I use for help creating my short-form videos!
      • Newegg: For all sorts of computer components!
      • Bulk Supplements: For an enormous selection of health supplements!
      • Quora: I try to answer questions on Quora when folks request them of me!

    author avatar
    Nick Cosentino Principal Software Engineering Manager
    Principal Software Engineering Manager at Microsoft. Views are my own.

    This Post Has 2 Comments

      1. Nick Cosentino

        Thanks for the comment!

        “If possible”, I agree. But I strongly disagree with “don’t return it” as a blanket statement.

        Personally, the thing that I hate about IEnumerable as a return type is that you don’t know if it’s backed by an iterator or just a collection being returned (I wish dotnet would introduce something where we could know this, or indicate this in a different way). It’s the difference between lazy evaluation or not, which can be a huge difference in how things operate. However, IEnumerable when you’re always bubbling up a more concrete collection anyway feels kind of silly to me. Definitely more likely to use something like IReadOnlyList or IReadOnlyCollection for that.

        However, leveraging IEnumerable allows you to write code that can stream data sources. The flexibility of being able to write code like this I feel like is too powerful to ignore. At least for the stuff I find myself writing and working with.

        Again, these are all just my opinions. The great thing is everyone can make their own decisions and write code how they’d prefer 🙂

    Leave a Reply