Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
You use the yield
statement in an iterator to provide the next value or signal the end of an iteration. The yield
statement has the two following forms:
yield return
: to provide the next value in iteration, as the following example shows:
foreach (int i in ProduceEvenNumbers(9))
{
Console.Write(i);
Console.Write(" ");
}
// Output: 0 2 4 6 8
IEnumerable<int> ProduceEvenNumbers(int upto)
{
for (int i = 0; i <= upto; i += 2)
{
yield return i;
}
}
yield break
: to explicitly signal the end of iteration, as the following example shows:
Console.WriteLine(string.Join(" ", TakeWhilePositive(new int[] {2, 3, 4, 5, -1, 3, 4})));
// Output: 2 3 4 5
Console.WriteLine(string.Join(" ", TakeWhilePositive(new int[] {9, 8, 7})));
// Output: 9 8 7
IEnumerable<int> TakeWhilePositive(IEnumerable<int> numbers)
{
foreach (int n in numbers)
{
if (n > 0)
{
yield return n;
}
else
{
yield break;
}
}
}
Iteration also finishes when control reaches the end of an iterator.
In the preceding examples, the return type of iterators is IEnumerable<T> (in nongeneric cases, use IEnumerable as the return type of an iterator). You can also use IAsyncEnumerable<T> as the return type of an iterator. That makes an iterator async. Use the await foreach
statement to iterate over iterator's result, as the following example shows:
await foreach (int n in GenerateNumbersAsync(5))
{
Console.Write(n);
Console.Write(" ");
}
// Output: 0 2 4 6 8
async IAsyncEnumerable<int> GenerateNumbersAsync(int count)
{
for (int i = 0; i < count; i++)
{
yield return await ProduceNumberAsync(i);
}
}
async Task<int> ProduceNumberAsync(int seed)
{
await Task.Delay(1000);
return 2 * seed;
}
IEnumerator<T> or IEnumerator can also be the return type of an iterator. Use those return types when you implement the GetEnumerator
method in the following scenarios:
You design the type that implements IEnumerable<T> or IEnumerable interface.
You add an instance or extension GetEnumerator
method to enable iteration over the type's instance with the foreach
statement, as the following example shows:
public static void Example()
{
var point = new Point(1, 2, 3);
foreach (int coordinate in point)
{
Console.Write(coordinate);
Console.Write(" ");
}
// Output: 1 2 3
}
public readonly record struct Point(int X, int Y, int Z)
{
public IEnumerator<int> GetEnumerator()
{
yield return X;
yield return Y;
yield return Z;
}
}
You can't use the yield
statements in:
yield
was invalid in any method with an unsafe
block. Beginning with C# 13, you can use yield
in methods with unsafe
blocks, but not in the unsafe
block.yield return
and yield break
can not be used in catch and finally blocks, or in try blocks with a corresponding catch
block. The yield return
and yield break
statements can be used in a try
block with no catch
blocks, only a finally
block.The call of an iterator doesn't execute it immediately, as the following example shows:
var numbers = ProduceEvenNumbers(5);
Console.WriteLine("Caller: about to iterate.");
foreach (int i in numbers)
{
Console.WriteLine($"Caller: {i}");
}
IEnumerable<int> ProduceEvenNumbers(int upto)
{
Console.WriteLine("Iterator: start.");
for (int i = 0; i <= upto; i += 2)
{
Console.WriteLine($"Iterator: about to yield {i}");
yield return i;
Console.WriteLine($"Iterator: yielded {i}");
}
Console.WriteLine("Iterator: end.");
}
// Output:
// Caller: about to iterate.
// Iterator: start.
// Iterator: about to yield 0
// Caller: 0
// Iterator: yielded 0
// Iterator: about to yield 2
// Caller: 2
// Iterator: yielded 2
// Iterator: about to yield 4
// Caller: 4
// Iterator: yielded 4
// Iterator: end.
As the preceding example shows, when you start to iterate over an iterator's result, an iterator is executed until the first yield return
statement is reached. Then, the execution of an iterator is suspended and the caller gets the first iteration value and processes it. On each subsequent iteration, the execution of an iterator resumes after the yield return
statement that caused the previous suspension and continues until the next yield return
statement is reached. The iteration completes when control reaches the end of an iterator or a yield break
statement.
For more information, see The yield statement section of the C# language specification.
.NET feedback
.NET is an open source project. Select a link to provide feedback:
Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register now