0
0
CsharpHow-ToBeginner · 4 min read

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 foreach to consume the async stream, which causes compilation errors.
  • Forgetting to mark the iterator method as async when using yield return with asynchronous operations.
  • Using blocking calls like .Result or .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

ConceptDescription
IAsyncEnumerableInterface for async streams of data.
async IAsyncEnumerable MethodDefines an async iterator method.
yield returnProduces each item asynchronously.
await foreachConsumes async streams with await.
CancellationTokenOptional 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.