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
43bb966e-850b-4da5-a3f3-2b7c63ca7601|0|.0
Category:
Tags: