Does an IEnumerable have to use Yield to be deferred?
Here is test code which has helped me understand deferred execution and yield.
//immediate execution
public IEnumerable Power(int number, int howManyToShow)
{
var result = new int[howManyToShow];
result[0] = number;
for (int i = 1; i < howManyToShow; i++)
result[i] = result[i - 1] * number;
return result;
}
//deferred but eager
public IEnumerable PowerYieldEager(int number, int howManyToShow)
{
var result = new int[howManyToShow];
result[0] = number;
for (int i = 1; i < howManyToShow; i++)
result[i] = result[i - 1] * number;
foreach (var value in result)
yield return value;
}
//deferred and lazy
public IEnumerable PowerYieldLazy(int number, int howManyToShow)
{
int counter = 0;
int result = 1;
while (counter++ < howManyToShow)
{
result = result * number;
yield return result;
}
}
[Test]
public void Power_WhenPass2AndWant8Numbers_ReturnAnEnumerable()
{
IEnumerable listOfInts = Power(2, 8);
foreach (int i in listOfInts)
Console.Write("{0} ", i);
}
[Test]
public void PowerYieldEager_WhenPass2AndWant8Numbers_ReturnAnEnumerableOfInts()
{
//deferred but eager execution
IEnumerable listOfInts = PowerYieldEager(2, 8);
foreach (int i in listOfInts)
Console.Write("{0} ", i);
}
[Test]
public void PowerYield_WhenPass2AndWant8Numbers_ReturnAnEnumerableOfIntsOneAtATime()
{
//deferred and lazy execution
IEnumerable listOfInts = PowerYieldLazy(2, 8);
foreach (int i in listOfInts)
Console.Write("{0} ", i);
}
It doesn’t have to use
yield– ultimately you can do everything thatyielddoes, by writing a custom enumerator (IEnumerator[<T>]) and delaying the action until the firstMoveNext(). However, that is pretty painful to implement. Certainly if you do useyield, the implementation is deferred by default (you can make it non-deferred by using two methods – one that doesn’t useyield, which then after accessing the data uses the other method (an iterator block) to implement the enumerator.Frankly, writing enumerators is hard and buggy. I avoid it unless absolutely necessary. Iterator blocks are great.