When i have a code block
static void Main()
{
foreach (int i in YieldDemo.SupplyIntegers())
{
Console.WriteLine("{0} is consumed by foreach iteration", i);
}
}
class YieldDemo
{
public static IEnumerable<int> SupplyIntegers()
{
yield return 1;
yield return 2;
yield return 3;
}
}
can i interpret the principle behind yield return as
|1| |2| |3| are stored in contiguous memory block.Pointer of "IEnumerator" Moves to |1|
Clarifications :
(1) Normally we will have one valid return statement is allowed inside a function.How does C# treats when multiple yield return ,yield return,... statements are present?
(2) Once the return is encountered there is no way for control again coming back to SupplyIntegers(), in case it is allowed won't the Yield again starts from 1 ? I mean yield return 1?
yield return is used with enumerators. On each call of yield statement, control is returned to the caller but it ensures that the callee's state is maintained. Due to this, when the caller enumerates the next element, it continues execution in the callee method from statement immediately after the yield statement.
You use a yield return statement to return each element one at a time. The sequence returned from an iterator method can be consumed by using a foreach statement or LINQ query. Each iteration of the foreach loop calls the iterator method.
The yield return statement returns one element at a time. The return type of yield keyword is either IEnumerable or IEnumerator . The yield break statement is used to end the iteration. We can consume the iterator method that contains a yield return statement either by using foreach loop or LINQ query.
In the iterator block, the yield keyword is used together with the return keyword to provide a value to the enumerator object. This is the value that is returned, for example, in each loop of a foreach statement. The yield keyword is also used with break to signal the end of iteration."
Nope - far from it; I'll write a long-hand version for you... it is too grungy!
Note it also helps if you understand that the foreach
is actually:
using(var iterator = YieldDemo.SupplyIntegers().GetEnumerator()) {
int i;
while(iterator.MoveNext()) {
i = iterator.Current;
Console.WriteLine("{0} is consumed by foreach iteration", i);
}
}
using System;
using System.Collections;
using System.Collections.Generic;
static class Program
{
static void Main()
{
foreach (int i in YieldDemo.SupplyIntegers())
{
Console.WriteLine("{0} is consumed by foreach iteration", i);
}
}
}
class YieldDemo
{
public static IEnumerable<int> SupplyIntegers()
{
return new YieldEnumerable();
}
class YieldEnumerable : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new YieldIterator();
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
class YieldIterator : IEnumerator<int>
{
private int state = 0;
private int value;
public int Current { get { return value; } }
object IEnumerator.Current { get { return Current; } }
void IEnumerator.Reset() { throw new NotSupportedException(); }
void IDisposable.Dispose() { }
public bool MoveNext()
{
switch (state)
{
case 0: value = 1; state = 1; return true;
case 1: value = 2; state = 2; return true;
case 2: value = 3; state = 3; return true;
default: return false;
}
}
}
}
As you can see, it builds a state machine in the iterator, with the state machine progressed by MoveNext
. I've used the pattern with a state
field, as you can see how this would work for more complex iterators.
Importantly:
finally
block (including using
), it goes in the Dispose()
yield return
become a case
(roughly)yield break
becomes a state = -1; return false;
(or similar)The way the C# compiler does this is very complicated, but it makes writing iterators a breeze.
It's just a syntax sugar, .net generates IEnumerator class for you and implements MoveNext, Current and Reset methods, than generates IEnumarable class GetEnumerator of which returns that IEnumerator, you can see that magic classes by .net reflector or ildasm.
Also see here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With