Apparently I don't understand iterator blocks

by abutler 7. April 2011 14:37

Ran into something interesting today, which revealed a big hole in my knowledge of iterator blocks / the yield statement.  Sample code:

 

 

using System;
using System.Collections.Generic;

class Program
{
	static void Main(string[] args)
	{
		SplitChars(null);
		
		Console.ReadKey();
	}		

	static IEnumerable<char> SplitChars(string input)
	{
		if (input == null)
			throw new ArgumentNullException("input");

		for (int i = 0; i < input.Length; i++)
		{
			yield return input[i];
		}

		Console.WriteLine(input);
	}
}

 

 

I expected this to fail the method's argument validation.  It runs without throwing the exception.  Turns out a quick trip to StackOverflow revealed what is really going here.  Turns out until you use the result of an block as an iterator block, nothing is executed.  So if we run the sample code like this:

 

 

using System;
using System.Collections.Generic;

class Program
{
	static void Main(string[] args)
	{
		foreach (char c in SplitChars(null))
		{
			Console.WriteLine(c);
		}
		Console.ReadKey();
	}		

	static IEnumerable<char> SplitChars(string input)
	{
		if (input == null)
			throw new ArgumentNullException("input");

		for (int i = 0; i < input.Length; i++)
		{
			yield return input[i];
		}

		Console.WriteLine(input);
	}
}

 

 

Now we get the expected exception.  I'm probably the only one who would be surprised by this behavior, although it makes sense now that I have read about how the code generation involved, etc.

Some links on this subject:

http://stackoverflow.com/questions/2504352/c-yield-in-nested-method/2504369#2504369

http://blogs.msdn.com/b/oldnewthing/archive/2008/08/12/8849519.aspx

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading


About the authors

We like to rock ICS Bank 2

Month List