Throw Before You Yield

In a comment left by Bart De Smet, he pointed out that I failed to address the fact that the execution of all “yielding” methods is deferred.

For instance, when running the following code, no exceptions will be thrown:

int[] arr = null;
var copy = arr.Enumerate();



// ...

static IEnumerable<T> Enumerate<T>(this IEnumerable<T> enumeration)
{
// Check to see that enumeration is not null
if (enumeration == null)
throw new ArgumentNullException("enumeration");

foreach (var item in enumeration)
{
yield return item;
}
}

This is because the first time the code from the method will run will be after there a call to copy‘s GetEnumerator(), followed by a call to that object’s MoveNext() method has been made (i.e. when we enumerate over copy).

To overcome this problem, we’ll change the code slightly:

static IEnumerable<T> Enumerate<T>(this IEnumerable<T> enumeration)
{
// Check to see that enumeration is not null
if (enumeration == null)
throw new ArgumentNullException("enumeration");

return EnumerateCore(enumeration);
}

private static IEnumerable<T> EnumerateCore<T>(IEnumerable<T> enumeration)
{
foreach (var item in enumeration)
{
yield return item;
}
}

Now a NullReferenceException will immediately be thrown out of Enumerate, since the “unyielding” method will first run the code and then defer-call to the “yielding” method. This helps our “yielding” methods adhere to the principal of fail-fast.

Advertisements

3 thoughts on “Throw Before You Yield

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