IEnumerable Guard Clause Best Practice

IEnumerable is C#’s built-in implementation of the iterator design pattern. It’s very powerful. Below is how to iterate through IEnumerable in C#:


IEnumerable GetInts()
{
    var nums = new[] { 1, 2, 3, 4 };

    foreach (int num in nums)
    {
        yield return num;
    }
}

int main()
{
    foreach(int num in GetInts())
    {
        Console.Out.WriteLine(num);
    }
}

The Gotcha.

IEnumerable defers execution until code actually acts on the elements returned from IEnumerable. This also defers execution of throwing exceptions, which can make debugging more difficult. Here is some code to illustrate the problem:


IEnumerable DoesNotCrashImmediately(bool crash)
{
    if (crash)
        throw new InvalidProgramException();

    var nums = new[] { 1, 2, 3, 4 };

    foreach (int num in nums)
    {
        yield return num;
    }
}

IEnumerable CrashesImmediately(bool crash)
{
    if(crash)
        throw new InvalidProgramException();

    return CrashesImmediatelyImpl();
}

IEnumerable CrashesImmediatelyImpl()
{
    var nums = new[] { 1, 2, 3, 4 };

    foreach (int num in nums)
    {
        yield return num;
    }
}

[TestMethod]
public void Crashes_Third()
{
    var first = DoesNotCrashImmediately(crash: true);
    var second = first.Where(x => x > 3);
    int third = second.SingleOrDefault();

    Assert.AreNotEqual(0, third);
}

[TestMethod]
public void Crashes_First()
{
    var first = CrashesImmediately(crash: true);
    var second = first.Where(x => x > 3);
    int third = second.SingleOrDefault();

    Assert.AreNotEqual(0, third);
}

When guard clauses are grouped with yield statements, they are deferred until the yield statements are called. As a result the guard clauses are not executed until a an undefined time later in the programs execution.

Below NCrunch is used to highlight what code within the unit tests was actually hit. Red circles on the left indicate how far the code executed before throwing an exception.

Summary

Create separate methods with guard clauses when returning IEnumerable!

Advertisements
This entry was posted in C#, Unit Testing and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s