如何在Linq查询中等待方法

如何在Linq查询中等待方法,linq,windows-runtime,async-await,c#-5.0,winrt-async,Linq,Windows Runtime,Async Await,C# 5.0,Winrt Async,尝试在LINQ查询中使用wait关键字,我得到以下结果: 只能在初始“from”子句的第一个集合表达式或“join”子句的集合表达式中的查询表达式中使用“await”运算符 示例代码: var data = (from id in ids let d = await LoadDataAsync(id) select d); 不能在LINQ查询中等待某些内容,还是需要以不同的方式对其进行结构化?LINQ对async/await的支持非常有限。对于l

尝试在
LINQ
查询中使用
wait
关键字,我得到以下结果:

只能在初始“from”子句的第一个集合表达式或“join”子句的集合表达式中的查询表达式中使用“await”运算符

示例代码:

var data = (from id in ids
            let d = await LoadDataAsync(id)
            select d);

不能在
LINQ
查询中等待某些内容,还是需要以不同的方式对其进行结构化?

LINQ对
async
/
await
的支持非常有限。对于linqto对象,我所知道的唯一真正有用的操作是使用
async
委托执行
Select
(这会产生一系列任务)


您可以自己定义一些异步linq操作(对于linq to对象): 例如:您可以编写自己的wheresync扩展方法:

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);
}
公共静态异步任务同步(
此IEnumerable目标,Func predicateAsync)
{
var tasks=target.Select(异步x=>new{Predicate=await-predicateAsync(x).ConfigureAwait(false),Value=x}).ToArray();
var results=await Task.WhenAll(tasks).ConfigureAwait(false);
返回结果。其中(x=>x.Predicate)。选择(x=>x.Value);
}
然后像这样使用它:

var ints = new List<int> { 1, 2, 3 };
var smallInts = await ints.WhereAsync(IsSmallIntAsync);
var ints=新列表{1,2,3};
var smallInts=等待ints.wheresync(IsSmallIntAsync);

使用反应式扩展,可以异步处理linq查询的结果,如下所示:

(from d in ids
select LoadDataAsync(d).ToObservable()).Merge()
这将为您提供一个可观察的流,您可以以各种方式作出响应。例如,您可以将结果缓冲到带有超时的列表中


上述内容实质上是说“对于ids中的每个d,对其应用一个异步函数,该函数为每个d生成一个任务,并将其视为单个结果的可观测值(ToObservable),并将所有这些可观测值一起视为单个可观测流(Merge)

我想这里涉及的编译器魔法太多了,你需要用不同的结构,把它写成一个普通的foreach-loop。这会比Parallel.foreach-loop更好吗?如果
LoadData
是I/O绑定的,那会更好。Wonderfull!LoadData是一个I/O过程。我将
LoadData
重命名为
LoadDataAsync
这样就更清楚了,如果没有
等待
这个方法,它会返回一个
任务
,因此
什么时候所有的
方法都会工作。@StephenCleary
选择
的特殊之处在于“我所知道的唯一真正有用的操作是使用异步委托进行选择”“与
Where
?相反,这种方法使用的是sync over async,正如我在博客上解释的那样)。@StephenCleary是的,我明白了,我讨厌configurewait代码编写,我不知道为什么默认设置会使用上下文。我修正了这个问题。它仍然容易死锁,除非用户总是在谓词中使用
ConfigureAwait
。并且只使用使用
ConfigureAwait
的库(即,HttpClient在某些平台上不支持)。@StephenCleary在访问结果之前,我确实在等待任务,我认为这会改变任务的行为。结果是非阻塞的。我如何才能等待所有任务并随后访问结果?对不起,我完全错过了第一个
wait
。我仍然建议您使用
wait
来检索结果,以避免
AggregateException
,但代码不存在通过异步进行同步的问题。
var ints = new List<int> { 1, 2, 3 };
var smallInts = await ints.WhereAsync(IsSmallIntAsync);
(from d in ids
select LoadDataAsync(d).ToObservable()).Merge()