Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert async loop to LINQ query

I have this straightforward loop that I'd like to write declaratively, using LINQ.

    async Task<Foo> GetFooAsync(string fooId, CancellationToken cancellationToken = default(CancellationToken))
    {
        foreach (var source in FooSources)
        {
            var result = await source.GetFooAsync(fooId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
            if (result != null)
            {
                return result;
            }
        }
        return null;
    }

I wish for something that looks like:

return FooSources.Where(...).FirstOrDefault();

I'm stuck, especially on making LINQ and async/await work together.

like image 308
Jay Bazuzi Avatar asked May 31 '13 21:05

Jay Bazuzi


1 Answers

Your options for async LINQ are very limited. As the other answer pointed out, you can use async methods in Select, but that's about it:

var tasks = FooSources.Select(source => source.GetFooAsync(fooId, cancellationToken));

This will get you a sequence of Task<Foo>. You can then await for them all to complete:

var results = await Task.WhenAll(tasks);

Now you have an array of Foo, which can be filtered:

return results.Where(foo => foo != null);

Note that this has very different semantics than your original code. Your original code will await each source before starting the next; this answer will start all sources going, and then await them all.

If you want foreach semantics and need to await inside the loop, then the correct solution is to use a foreach loop containing an await. There is no direct LINQ equivalent.

like image 64
Stephen Cleary Avatar answered Oct 14 '22 13:10

Stephen Cleary