Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yield return and exception handling [duplicate]

I just had a case with a method using yield return not throwing an ArgumentException which I expected. I have reconstructed the case with the simpliest possible classes here:

class Program
{
    static void Main(string[] args)
    {
        try
        {
            var listA = FooA(count: 0);
            Console.WriteLine("A did not throw exception!");
        }
        catch (ArgumentException)
        {
            Console.WriteLine("A threw exception!");
        }

        try
        {
            var listB = FooB(count: 0);
            Console.WriteLine("B did not throw exception!");
        }
        catch (ArgumentException)
        {
            Console.WriteLine("B threw exception!");
        }

        Console.ReadLine();
    }

    private static IEnumerable<int> FooA(int count)
    {
        if(count == 0)
            throw new ArgumentException("Count must be above 0");
        var list = new List<int>();
        for (var i = 0; i < count; i++)
        {
            list.Add(i);
        }
        return list;
    }

    private static IEnumerable<int> FooB(int count)
    {
        if (count == 0)
            throw new ArgumentException("Count must be above 0");
        for (var i = 0; i < count; i++)
        {
            yield return i;
        }
    }
}

Output:

A threw exception!
B did not throw exception!

Can some one please explain to me why FooB does not throw an exception while FooA does?

like image 227
Stephan Møller Avatar asked Feb 18 '16 13:02

Stephan Møller


Video Answer


1 Answers

It's because FooB is never even evaluated.

When you call a method, that method is called immediately. When you use yield and return an enumerable, that method is only called when something needs to use the value returned, and only a single item at a time; this is the benefit of yielding.

So, if you add something that uses the value

try
{
    var listB = FooB(count: 0);
    Console.WriteLine(listB.First()); // use the IEnumerable returned
    Console.WriteLine("B did not throw exception!");
}
catch (ArgumentException)
{
    Console.WriteLine("B threw exception!");
}

You will see your expected result.

like image 82
DrewJordan Avatar answered Sep 17 '22 14:09

DrewJordan