Search code examples
c#linqasync-awaitiasyncenumerable

Combine AsyncEnumerable with SelectMany (synchronous?)


I try to use an AsyncEnumerable that returns a list of items in each yield and try to use SelectMany (or SelectManyAsync) to retrieve all items.

Working sample:

IAsyncEnumerable<IReadOnlyList<...>> source = ...;
await foreach (var list in source)
{
    foreach (var item in list)
    {
        // Perform some action on item
    }
}

But I try to use linq for that like:

IAsyncEnumerable<IReadOnlyList<...>> source = ...;
var items = from list in source
            from item in list
            where ...
            select item;
await foreach (var item in items)
{
    ...
}

Or in method syntax:

IAsyncEnumerable<IReadOnlyList<...>> source = ...;
var items = source
    .SelectMany(static list => list)
    .Where(...);
await foreach (var item in items)
{
    ...
}

But I got an error from compiler:

CS0411: The type arguments for Method 'AsyncEnumerable.SelectMany....)' cannot be inferred from usage.

Is there any way to use the synchronous linq extensions after awaiting the AsyncEnumerable or is the working sample the only way of handling such problems?

EDIT

What I'm looking for is an extension method like the following one that is supported by linq query syntax:

public static async IAsyncEnumerable<T> SelectMany<TCollection, T>(this IAsyncEnumerable<TCollection> self, Func<TCollection, IEnumerable<T>> selector)
    where TCollection : IEnumerable<T>
{
    await foreach (var collection in self)
    {
        foreach (var item in selector(collection))
        {
            yield return item;
        }
    }
}

Is there any extension method like this one?


Solution

  • using <PackageReference Include="System.Linq.Async" Version="6.0.1" />

    IAsyncEnumerable<IReadOnlyList<string>> source = new[] { new[] { "1", "2" } }.ToAsyncEnumerable();
    var result = source.SelectMany(list => list.ToAsyncEnumerable());
    await foreach (var s in result)
    {
        Console.WriteLine(s);
    }