C# Language Yield Keyword Correctly checking arguments

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Insert
> Step 2: And Like the video. BONUS: You can also share it!

Example

An iterator method is not executed until the return value is enumerated. It's therefore advantageous to assert preconditions outside of the iterator.

public static IEnumerable<int> Count(int start, int count)
{
    // The exception will throw when the method is called, not when the result is iterated
    if (count < 0)
        throw new ArgumentOutOfRangeException(nameof(count));

    return CountCore(start, count);
}

private static IEnumerable<int> CountCore(int start, int count)
{
    // If the exception was thrown here it would be raised during the first MoveNext()
    // call on the IEnumerator, potentially at a point in the code far away from where
    // an incorrect value was passed.
    for (int i = 0; i < count; i++)
    {
        yield return start + i;
    }
}

Calling Side Code (Usage):

// Get the count
var count = Count(1,10);
// Iterate the results
foreach(var x in count)
{
    Console.WriteLine(x);
}

Output:

1
2
3
4
5
6
7
8
9
10

Live Demo on .NET Fiddle

When a method uses yield to generate an enumerable the compiler creates a state machine that when iterated over will run code up to a yield. It then returns the yielded item, and saves its state.

This means you won't find out about invalid arguments (passing null etc.) when you first call the method (because that creates the state machine), only when you try and access the first element (because only then does the code within the method get ran by the state machine). By wrapping it in a normal method that first checks arguments you can check them when the method is called. This is an example of failing fast.

When using C# 7+, the CountCore function can be conveniently hidden into the Count function as a local function. See example here.



Got any C# Language Question?