8

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?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Stephan Møller
  • 1,247
  • 19
  • 39

1 Answers1

12

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.

DrewJordan
  • 5,266
  • 1
  • 25
  • 39