yield return lets an iterator method produce sequence elements one at a time for direct use in foreach. Each element is generated when requested, rather than after constructing the entire sequence. section 2.2
The compiler transforms the iterator into an enumerable and enumerator. It divides the method into resumable chunks, tracks the current step, and advances through those chunks from MoveNext; the .NET runtime does not suspend and resume the original method directly. section 2.2 section 2.3
The feature changes sequence production in several practical ways:
- A list-based method generates and stores all values before foreach consumes them. section 2.2
- A yield-based method resumes only far enough to produce the next value, then pauses until the iterator advances again. section 2.2
- Iterator methods use IEnumerable<T>; their generated enumerators expose Current and MoveNext, with MoveNext returning false after the final value. section 2.2
- The same compiler-transformation pattern provides a simpler route to understanding async/await without immediately introducing multithreading complexity. section 2.0
Listing 2.4 Using yield return
private IEnumerable<int> YieldDemo()
{
yield return 1;
yield return 2;
}
public void UseYieldDemo()
{
foreach(var current in YieldDemo())
{
Console.WriteLine($"Got {current}");
}
}
Compare a minimal yield iterator with a list-based equivalent: both emit 1 and 2, but yield defers each value until foreach requests it. section 2.2
For asynchronous sequences, mark the method async, return IAsyncEnumerable<T>, and combine await with yield return. Consume the result with await foreach; WithCancellation can pass a cancellation token, but iteration stops only when code checks that token. section 14.8 section 14.0









