How to await a method in a Linq query

生来就可爱ヽ(ⅴ<●) 提交于 2019-11-28 10:53:10
Stephen Cleary

LINQ has very limited support for async/await. For LINQ-to-objects, the only really useful operation I know of is to do a Select with an async delegate (which results in a sequence of tasks).

List<T> data = new List<T>();
foreach (var id in ids)
  data.Add(await LoadDataAsync(id));

If you can do LoadDataAsync in parallel safely, your example could be rewritten as:

T[] data = await Task.WhenAll(ids.Select(id => LoadDataAsync(id)));
Console

You can define some async linq operations by yourself (for linq to objects): for example: you can write your own WhereAsync extension method:

public static async Task<IEnumerable<T>> WhereAsync<T>(
this IEnumerable<T> target, Func<T, Task<bool>> predicateAsync)
{
   var tasks = target.Select(async x => new { Predicate = await predicateAsync(x).ConfigureAwait(false), Value = x }).ToArray();
   var results = await Task.WhenAll(tasks).ConfigureAwait(false);

   return results.Where(x => x.Predicate).Select(x => x.Value);
}

And use it like that:

var ints = new List<int> { 1, 2, 3 };
var smallInts = await ints.WhereAsync(IsSmallIntAsync);

Using reactive extensions, it is possible to handle the results of a linq query asynchronously like this:

(from d in ids
select LoadDataAsync(d).ToObservable()).Merge()

This is gives you an observable stream you can respond to in various ways. For example, you can then .Buffer the results into a list with a timeout.

The above in essence says "for every d in ids, apply an asynchronous function to it, which yields a task for each d, and treat that as an observable of an individual result (ToObservable), and treat all those observables together as a single observable stream (Merge)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!