ICYMI C# 9 New Features: Adding foreach Support To Any Type

This is part of a series of articles on new features introduced in C# 9.

Prior to C# 9 you could add foreach support to a class by modifying the class and implementing the IEnumerable interface. With C# 9 you can add foreach support to an existing class without actually needing to modify that class.

As an example, suppose the following class exists in our codebase:

public class Choices
{
    public string FirstChoice { get; set; }
    public string SecondChoice { get; set; }
    public string ThirdChoice { get; set; }
    public string FourthChoice { get; set; }
    public string FifthChoice { get; set; }
}

Because the class is in our control we could add the ability to foreach through all the choices (FirstChoice, SecondChoice, etc.).

One way to do this would be to modify the Choices class and implement IEnumerable – we could also just create a method called GetEnumerator and then have it return a class which has a MoveNext and Current method:

public class ChoicesEnumerator
{
    public string[] _choices = new string[5];

    int position = -1;

    public ChoicesEnumerator(Choices choices)
    {
        // Additional null/validation/etc checking code omitted

        _choices[0] = choices.FirstChoice;
        _choices[1] = choices.SecondChoice;
        _choices[2] = choices.ThirdChoice;
        _choices[3] = choices.FourthChoice;
        _choices[4] = choices.FifthChoice;
    }

    public bool MoveNext()
    {
        position++;
        return position < _choices.Length;
    }

    public string Current
    {
        get
        {
            try
            {
                return _choices[position];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }
}

We could then modify the Choices class and add the GetEnumerator method:

public class Choices
{
    public string FirstChoice { get; set; }
    public string SecondChoice { get; set; }
    public string ThirdChoice { get; set; }
    public string FourthChoice { get; set; }
    public string FifthChoice { get; set; }
    
    public ChoicesEnumerator GetEnumerator()
    {
        return new ChoicesEnumerator(this);
    }
}

Now we can iterate through the choices in a foreach loop:

var choices = new Choices
{
    FirstChoice = "Orange",
    SecondChoice = "Blue",
    ThirdChoice = "Green",
    FourthChoice = "Cyan",
    FifthChoice = "Grey"
};

foreach (var choice in choices)
{
    WriteLine(choice);
}

But what if we were not able to modify the Choices class – for example if it is from an external library? From C# 9 you can follow a similar approach to the above but add the foreach support using an extension method. This way we don’t have to modify the original class.

If the original class that we couldn’t modify looked like the following:

public sealed class Choices
{
    public string FirstChoice { get; set; }
    public string SecondChoice { get; set; }
    public string ThirdChoice { get; set; }
    public string FourthChoice { get; set; }
    public string FifthChoice { get; set; }
}

We could once again create the ChoicesEnumerator class as above and then just create an extension method that adds the GetEnumerator method to the Choices class, without needing to modify the Choices class itself:

public static class ChoicesExtensions
{
    public static ChoicesEnumerator GetEnumerator(this Choices choices)
    {
        return new ChoicesEnumerator(choices);
    }
}

Now we can once again foreach through all the choices.

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

Add comment

Loading