使用ForEachAsync和Action内部的await时不等待 [英] Doesn't await when using ForEachAsync with await inside Action
问题描述
以下内容应返回 C,但它返回 B
The following should return "C", but it returns "B"
using System.Data.Entity;
//...
var state = "A";
var qry = (from f in db.myTable select f);
await qry.ForEachAsync(async (myRecord) => {
await DoStuffAsync(myRecord);
state = "B";
});
state = "C";
return state;
它不等待DoStuffAsync完成, state = C
运行,然后执行 state = B
(因为它内部仍在等待)。
It doesn't wait for DoStuffAsync to complete, state="C"
runs through and then later state="B"
executes (because inside it is still awaiting).
推荐答案
这是因为ForEachAsync的实现不会等待委托的操作
That's because the implementation of ForEachAsync doesn't await the delegated action
moveNextTask = enumerator.MoveNextAsync(cancellationToken);
action(current);
但这是因为,您不能等待操作,委托必须是一个返回任务的Func,请参见如何实现异步操作委托方法?
But that is because, you can't await an action, the delegate needs to be a Func which returns a Task - see How do you implement an async action delegate method?
因此,在Microsoft提供包括Func委托的签名并在等待之前调用它之前,您必须滚动自己的扩展方法。我现在正在使用以下内容。
Therefore, until Microsoft provides a signature which includes a Func delegate and calls it with await, you'll have to roll your own extension method. I'm using the following at the moment.
public static async Task ForEachAsync<T>(
this IQueryable<T> enumerable, Func<T, Task> action, CancellationToken cancellationToken) //Now with Func returning Task
{
var asyncEnumerable = (IDbAsyncEnumerable<T>)enumerable;
using (var enumerator = asyncEnumerable.GetAsyncEnumerator())
{
if (await enumerator.MoveNextAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false))
{
Task<bool> moveNextTask;
do
{
var current = enumerator.Current;
moveNextTask = enumerator.MoveNextAsync(cancellationToken);
await action(current); //now with await
}
while (await moveNextTask.ConfigureAwait(continueOnCapturedContext: false));
}
}
}
有了这个,原始测试您的OP中的代码将按预期工作。
With this, the original test code in your OP will work as expected.
这篇关于使用ForEachAsync和Action内部的await时不等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!