2

Check out this program:

static class Program
{
  static void Main()
  {
    GetLinks();
    Console.WriteLine("Program failed!");
  }

  static IEnumerable<string> GetLinks()
  {
    throw new Exception();
    foreach (var item in new string[] { })
      yield return item;
  }
}

It's very weird but the result of this program is Program failed!, meaning the GetLinks function is not even called.
What's the explanation of this behavior?

Check it out for yourself.

Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632

3 Answers3

3

Iterator blocks are lazy. You need to call it by invoking it in a foreach or something. Code inside your iterator block will execute only on the first call to MoveNext which foreach will do for you.

As of now you're just preparing the query, you need to materialize it with the call to GetEnumerator followed by MoveNext.

For example following code will fail as expected.

static void Main()
{
    foreach(var item in GetLinks())
        Console.WriteLine(item );
    Console.WriteLine("Program failed!");
}

Further reading Iterator block implementation details

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • and here's the [documentation](https://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx): _"...Technical Implementation: The call to MyIteratorMethod doesn't execute the body of the method. Instead the call returns an IEnumerable into the elements variable..."_. So because the body of the method is not even executed, the exception is not raised. – Tim Schmelter Jan 23 '15 at 10:47
3

An iterator block is a somewhat special method... When it sees the yield return keyword, the compiler generates a class that implements IEnumerator<T> (and also IEnumerable<T>, depending on the return type of your method), and changes your method to return an instance of this class. The original body of your method is transformed into the MoveNext method of the enumerator. This means that the body of your method is only executed when the result is enumerated. Just calling the method has no effect if you don't enumerate the result. In other words, iterator blocks are executed lazily.

That's why methods implemented as iterator blocks must validate their arguments in a separate method:

public IEnumerable<string> Foo(string arg)
{
    if (arg == null) throw new ArgumentNullException();
    return FooIterator(arg);
}

private IEnumerable<string> FooIterator(string arg)
{
    yield return arg;
}
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
1

This is because of lazy execution. Try consuming the result of your function, e.g.:

GetLinks().First();
oleksii
  • 35,458
  • 16
  • 93
  • 163