liveBook · Manning

IAsyncEnumerator<T>

As explained in C# Concurrency: Asynchronous and multithreaded programming

IAsyncEnumerator<T> is a .NET generic interface that asynchronously advances through a sequence and exposes its current value.

IAsyncEnumerator<T> asynchronously advances through a sequence and exposes its current value. Current returns T, MoveNextAsync returns ValueTask<bool>, and DisposeAsync returns ValueTask. section 14.1

IAsyncEnumerable<T>.GetAsyncEnumerator returns the enumerator quickly; lengthy asynchronous initialization should begin when MoveNextAsync is first called. await foreach performs the await required at each iteration. section 14.1 section 14.8

Asynchronous iterator

An async iterator can yield 1, await Task.Delay(1000), then yield 2. The consumer uses await foreach to process each value as it becomes available. section 14.2

Table 14.2 IEnumerator vs. IAsyncEnumerator (view table figure)

IEnumerator<T>

IAsyncEnumerator<T>

T Current {get;}

T Current {get;}

bool MoveNext()

ValueTask<bool> MoveNextAsync()

void Dispose()

ValueTask DisposeAsync()

Compare IEnumerator<T> with IAsyncEnumerator<T>, including Current, MoveNextAsync, and asynchronous disposal. section 14.1

Listing 14.3 Code generated by the compiler from listing 14.2
public class AsyncYieldDemo_Enumerable : IAsyncEnumerable<int>
{
   public IAsyncEnumerator<int> GetAsyncEnumerator(CancellationToken _)
   {
      return new YieldDemo_Enumerator();
   }
}
 
public class YieldDemo_Enumerator : IAsyncEnumerator<int>
{
   public int Current { get; private set; }
 
   private async Task Step0()
   {
      Current = 1;
   }
   private async Task Step1()
   {
      await Task.Delay(1000);
      Current = 2;
   }
 
   private int _step = 0;
   public async ValueTask<bool> MoveNextAsync()
   {
      switch(_step)
      {
         case 0:
            await Step0();
            ++_step;
            break;
         case 1:
            await Step1();
            ++_step;
            break;
         case 2:
            return false;
      }
      return true;
   }
   public ValueTask DisposeAsync() => ValueTask.CompletedTask;
}
 
public IAsyncEnumerable<int> AsyncYieldDemo()
{
   return new AsyncYieldDemo_Enumerable();
}

Inspect the compiler-shaped enumerator, including generated state steps and MoveNextAsync. section 14.2

How C# Concurrency: Asynchronous and multithreaded programming covers it

How deep it goes
Explains interface members and compiler transformations, but defers detailed cancellation-token handling.
Examples
Uses an async iterator with Task.Delay and shows generated classes implementing IAsyncEnumerable<int> and IAsyncEnumerator<int>.
What it assumes
Assumes familiarity with IEnumerable<T>, IEnumerator<T>, yield return, and async/await.
What you can do after
Apply it via await foreach to consume asynchronously generated or retrieved data items.
How it connects
Connects IAsyncEnumerable<T> with IEnumerable<T>, IEnumerator<T>, async/await, yield return, and await foreach.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of C# Concurrency: Asynchronous and multithreaded programming. The section links point to the parts of the book it draws on.