Consider the following example:
class YieldTest
{
static void Main(string[] args)
{
var res = Create(new string[] { "1 12 123", "1234", "12345" });
}
static IEnumerable<int> Create(IEnumerable<string> strings)
{
foreach(string s in strings)
{
yield return s.Length;
if(s.Contains(' '))
{
string[] tokens = s.Split(' ');
foreach(string t in tokens)
{
yield return t.Length;
}
}
}
}
}
The call to Create
returns {8, 1, 2, 3, 4, 5}.
What really confuses me is that the code after the yield return statement is executed.
(Why would they name it yield return
and not just yield
??)
The documentation tells us
When a yield return statement is reached in the iterator method, expression is returned, and the current location in code is retained.
What does that mean? Where does a return occur? What is an iterator method?
It means your code is transformed into a state machine by the compiler.
When you call
Create
method, you'll get anIEnumerable<T>
. You can then callGetEnumerator()
on it and obtain anIEnumerator<T>
.Now, every time you call
MoveNext
on this iterator, your code will execute until it finds the firstyield
statement (whether it beyield return
oryield break
).If it hits a
yield return x
,MoveNext
returns true and the iterator'sCurrent
property will be set tox
, and the rest of the code will be executed the next time you callMoveNext
.This happens until either there's no more code to run or the code hits a
yield break
. At that point,MoveNext
will return false.Calling
MoveNext
on this piece of code will return true the first three times, and at each iteration,Current
will be set to 1, 2 and 3.Edit 2:
Regarding the
yield return ??
syntax, from Eric Lippert's Ambiguous Optional Parentheses, Part ThreeThe most important part of your quote is:
The iterator method does not return in a sense of exiting the method, otherwise you could only enumerate one item.
yield return
returns one element that is enumerated and then continues to run the code of the iterator method at the spot of theyield return
in order to return the next elements when it encounters the nextyield return
.An iterator method iterates over a collection and provides the single items by using
yield return
. These statements allow for a simplified implementation of the IEnumerable interface. In earlier versions of .NET, you had to implement a specific class as the enumerator. As this meant to introduce a lot of boilerplate code for each implementation of IEnumerable, theyield
statements were introduced to create an iterator method in a simpler way. Theyield return
statements in the iterator method provide a signal to the compiler that a new element is to be returned. When building the project, the compiler transfers the iterator method to an implementation of IEnumerable.An iterator method like this will run until it finds a yield return whenever you fetch a new value from the iterator that it produces. I believe technically it is when you call the
MoveNext
method of the Enumerator.When you call
MoveNext
the next time execution will resume from where it left off in the iterator method and keep going until it gets to the next yield return.Essentially every call to yield return in your iterator method will yield one of the values in your final enumerable.