Search code examples
c#.netasynchronoustaskiasyncenumerable

How can I run a async enumerator method synchronously and store it as an IEnumerable?


I have an async method that returns an IAsyncEnumerable using yield. In some cases, it may be needed to get the items synchronously so I want to make another method for this that returns IEnumerable by running the existing method synchronously in order to avoid duplicate code.

async IAsyncEnumerable<Foo> GetItemsAsync()
{
    yield return ...
}

IEnumerable<Foo> GetItems() => GetItemsAsync() // Run shyncronously

I read plenty solutions about running async methods synchronously using techniques like the Task.RunSynchronously or simply calling it in a sync context and ignoring the warning. However, it seems neither of these is possible in the case of async enumerables. The interface features no RunSynchronously method and trying to enumerate through it using a foreach that is not awaited causes a compilation error. Getting the enumerator and running MoveNext synchronously also doesn't seem to be an option since that method returns ValueTask which doesn't feature Wait methods and I need to capture the result of the task to know when to stop iterating.

So is it possible to force my async enomerator method synchronously and get the result as IEnumerable, and if so, how?


Solution

  • You could use the ToEnumerable extension method from the System.Linq.Async package. The signature of this method is:

    public static IEnumerable<TSource> ToEnumerable<TSource>(
        this IAsyncEnumerable<TSource> source)
    

    ...and you could use it like this:

    IEnumerable<Foo> GetItems() => GetItemsAsync().ToEnumerable();
    

    .NET 7 update: an extension method ToBlockingEnumerable with identical functionality is now included in .NET standard libraries:

    Converts an IAsyncEnumerable<T> instance into an IEnumerable<T> that enumerates elements in a blocking manner.