How to Use IAsyncEnumerable in C# for Asynchronous Streaming
Use
IAsyncEnumerable<T> in C# to asynchronously produce a sequence of values that can be awaited one by one using await foreach. Define an async iterator method with async IAsyncEnumerable<T> and yield values with yield return inside an async context.Syntax
The IAsyncEnumerable<T> interface represents an asynchronous stream of data. You create an async iterator method by marking it with async and returning IAsyncEnumerable<T>. Inside, use yield return to produce values asynchronously. To consume, use await foreach to iterate over the stream.
- async IAsyncEnumerable<T>: Declares an async iterator method.
- yield return: Produces each item in the stream.
- await foreach: Consumes the async stream asynchronously.
csharp
public async IAsyncEnumerable<int> GetNumbersAsync() { for (int i = 1; i <= 5; i++) { await Task.Delay(500); // simulate async work yield return i; } } public async Task ConsumeAsync() { await foreach (var number in GetNumbersAsync()) { Console.WriteLine(number); } }
Example
This example shows how to create an async iterator that yields numbers 1 to 5 with a delay, and how to consume it using await foreach. It demonstrates asynchronous streaming where each number is printed half a second apart.
csharp
using System; using System.Collections.Generic; using System.Threading.Tasks; class Program { static async IAsyncEnumerable<int> GetNumbersAsync() { for (int i = 1; i <= 5; i++) { await Task.Delay(500); // simulate async operation yield return i; } } static async Task Main() { await foreach (var number in GetNumbersAsync()) { Console.WriteLine(number); } } }
Output
1
2
3
4
5
Common Pitfalls
Common mistakes when using IAsyncEnumerable<T> include:
- Not using
await foreachto consume the async stream, which causes compilation errors. - Forgetting to mark the iterator method as
asyncwhen usingyield returnwith asynchronous operations. - Using blocking calls like
.Resultor.Wait()inside async iterators, which can cause deadlocks. - Not handling cancellation tokens to stop the async stream gracefully.
Example of wrong and right consumption:
csharp
/* Wrong: Trying to use regular foreach */ // foreach (var item in GetNumbersAsync()) { } // Error: Cannot use foreach without await /* Right: Use await foreach */ await foreach (var item in GetNumbersAsync()) { Console.WriteLine(item); }
Quick Reference
| Concept | Description |
|---|---|
| IAsyncEnumerable | Interface for async streams of data. |
| async IAsyncEnumerable | Defines an async iterator method. |
| yield return | Produces each item asynchronously. |
| await foreach | Consumes async streams with await. |
| CancellationToken | Optional parameter to cancel streaming. |
Key Takeaways
Use async iterator methods with async IAsyncEnumerable and yield return to produce async streams.
Consume IAsyncEnumerable with await foreach to handle data asynchronously.
Avoid blocking calls inside async iterators to prevent deadlocks.
Remember to mark iterator methods async when using await inside.
Consider supporting cancellation tokens for graceful stopping.