Using IEnumerable.Aggregate with Asynchronous Calls

I am trying to use the LINQ function IEnumerable.Aggregate to create a string consisting of files received through asynchronous calls. Not one hundred percent sure that this is possible, and I also know that there are other solutions, but I would like to try.

Now my code is as follows:

private static async Task<string> GetFiles(IEnumerable<string> filePaths)
{
    return filePaths.Aggregate(async (current, path) => current + await GetFile(path));
}

But the "asynchronous" inside the method call is marked with an error saying: "the return of the asynchronization method must be invalid, task or task." I get this error at all, but I'm not sure how to organize this particular case to avoid this. Any ideas?

UPDATE: To just clarify, the GetFile () method is really asynchronous and returns Task<string>:

private static async Task<string> GetFile(string filePath) { ... }

No need to go into specific code, but for those who are interested, it uses HttpClient.GetAsync(filePath)and returns it response.Content.ReadAsStringAsync().Result.

+4
source share
3 answers

Aggregatethe method will not work asynchronously. It does not support delegates based on tasks. You need to create a sequence of results yourself, waiting for it before calling the method Aggregate.

Something like this should work:

private static async Task<string> GetFiles(IEnumerable<string> filePaths)
{
    var files = filePaths
        .Select(p => GetFile(p))
        .ToArray();
    var results = await Task.WhenAll(files);

    return results
        .Aggregate((current, path) => current + path);
}
+5
source

As @Sriram said, LINQ async-awaitdoesn’t work as well, because there is no native support for async Task delegates.

What you can do is create an asynchronous overload of the unit yourself:

public static class AsynchronousEnumerable
{
    public static async Task<TSource> AggregateAsync<TSource>
                                      (this IEnumerable<TSource> source,
                                       Func<TSource, TSource, Task<TSource>> func)
    {
       using (IEnumerator<TSource> e = source.GetEnumerator())
       {
            if (!e.MoveNext())
            {
                throw new InvalidOperationException("Sequence contains no elements");
            }

            TSource result = e.Current;
            while (e.MoveNext()) result = await func(result, e.Current);
            return result;
        }
    }
}

:

private static Task<string> GetFiles(IEnumerable<string> filePaths)
{
    return filePaths.AggregateAsync(async (current, path) => current + 
                                                             await GetFile(path));
}
+5

async Aggregate, , - . , , Aggregate .

, , :

private static async Task<int> GetSumAsync(IEnumerable<Task<int>> numbers) {
  return await numbers
    .Aggregate(Task.FromResult(0), async (sumSoFar, nextNumber) => (await sumSoFar) + (await nextNumber));
}

, GetFiles. , Aggregate , ? ( "sum" )

+1

All Articles