While I was making a logic to iterate two enumerables, with different types, through a comparison, I found this:
class Program
{
public static IEnumerable<mm> YieldlyGet()
{
yield return new mm { Int = 0 };
yield return new mm { Int = 1 };
yield return new mm { Int = 2 };
yield return new mm { Int = 3 };
yield return new mm { Int = 4 };
yield return new mm { Int = 5 };
}
public static IEnumerable<int> YieldlyGetInt()
{
yield return 0;
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
}
public static IEnumerable<int> Get()
{
return new List<int> { 0, 1,2,3,4,5 };
}
static void Main(string[] args)
{
var yieldr = YieldlyGet().GetEnumerator();
var yieldv = YieldlyGetInt().GetEnumerator();
var list = Get().GetEnumerator();
int i = -1;
Console.WriteLine("For the current index: {0}", ++i);
Console.WriteLine("y-r: Should I move next? {0}, if yes, value: {1}", yieldr.MoveNext(), yieldr.Current != null ? yieldr.Current.Int : 0);
Console.WriteLine("y-v: Should I move next? {0}, if yes, value: {1}", yieldv.MoveNext(), yieldv.Current);
Console.WriteLine("l: Should I move next? {0}, if yes, value: {1}", list.MoveNext(), list.Current);
Console.WriteLine("For the current index: {0}", ++i);
Console.WriteLine("y-r: Should I move next? {0}, if yes, value: {1}", yieldr.MoveNext(), yieldr.Current != null ? yieldr.Current.Int : 0);
Console.WriteLine("y-v: Should I move next? {0}, if yes, value: {1}", yieldv.MoveNext(), yieldv.Current);
Console.WriteLine("l: Should I move next? {0}, if yes, value: {1}", list.MoveNext(), list.Current);
Console.WriteLine("For the current index: {0}", ++i);
Console.WriteLine("y-r: Should I move next? {0}, if yes, value: {1}", yieldr.MoveNext(), yieldr.Current != null ? yieldr.Current.Int : 0);
Console.WriteLine("y-v: Should I move next? {0}, if yes, value: {1}", yieldv.MoveNext(), yieldv.Current);
Console.WriteLine("l: Should I move next? {0}, if yes, value: {1}", list.MoveNext(), list.Current);
Console.WriteLine("For the current index: {0}", ++i);
Console.WriteLine("y-r: Should I move next? {0}, if yes, value: {1}", yieldr.MoveNext(), yieldr.Current != null ? yieldr.Current.Int : 0);
Console.WriteLine("y-v: Should I move next? {0}, if yes, value: {1}", yieldv.MoveNext(), yieldv.Current);
Console.WriteLine("l: Should I move next? {0}, if yes, value: {1}", list.MoveNext(), list.Current);
Console.WriteLine("For the current index: {0}", ++i);
Console.WriteLine("y-r: Should I move next? {0}, if yes, value: {1}", yieldr.MoveNext(), yieldr.Current != null ? yieldr.Current.Int : 0);
Console.WriteLine("y-v: Should I move next? {0}, if yes, value: {1}", yieldv.MoveNext(), yieldv.Current);
Console.WriteLine("l: Should I move next? {0}, if yes, value: {1}", list.MoveNext(), list.Current);
Console.WriteLine("For the current index: {0}", ++i);
Console.WriteLine("y-r: Should I move next? {0}, if yes, value: {1}", yieldr.MoveNext(), yieldr.Current != null ? yieldr.Current.Int : 0);
Console.WriteLine("y-v: Should I move next? {0}, if yes, value: {1}", yieldv.MoveNext(), yieldv.Current);
Console.WriteLine("l: Should I move next? {0}, if yes, value: {1}", list.MoveNext(), list.Current);
Console.WriteLine("For the current index: {0}", ++i);
Console.WriteLine("y-r: Should I move next? {0}, if yes, value: {1}", yieldr.MoveNext(), yieldr.Current != null ? yieldr.Current.Int : 0);
Console.WriteLine("y-v: Should I move next? {0}, if yes, value: {1}", yieldv.MoveNext(), yieldv.Current);
Console.WriteLine("l: Should I move next? {0}, if yes, value: {1}", list.MoveNext(), list.Current);
Console.ReadLine();
}
The thing is that, when I am after the last position, the list presents me with the default, whilst the yield created Iterator, keeps showing the last value.
For the current index: 6
y-r: Should I move next? False, if yes, value: 5
y-v: Should I move next? False, if yes, value: 5
l: Should I move next? False, if yes, value: 0
Why?
Let’s look what happen in enumerator, which used by
List<T>class (this is aList<int>.Enumerator). Actually msdn says that current value will be undefined, but we can analyze Framework 4.0 implementation. So, when enumerator is positioned after last elementMoveNextRarewill be called:Thus list is valid (unchanged) this method returns
defaut(T)value (which is0for int)What about generated enumerators? C# generates enumerator class, which will have states for each
yield returnstatements. Moving to next state setsCurrentvalue for this enumerator:What is interesting here is that
this.currentis not changed, after last assignment (when state was5). That’s why all subsequent calls toCurrentwill return value, which was set by lastyield returncall.