繁体   English   中英

通过Dispatcher调用异步lambda时双重等待

[英]Double await when invoke async lambda via Dispatcher

private async Task<T> LoadForm(WebControlAsync browser, Uri url)
{ ... }

var forms = await await _dispatcher.InvokeAsync(async () => await LoadForm(browser, form.Url));

我不明白为什么我必须在这里使用两个await来获取forms T 因此看起来InvokeAsync返回Task<Task<T>> 但是当我调用这样的同步方法时:

var forms = await _dispatcher.InvokeAsync(() => FillForm(forms, url));

它只需要一个await 所以原因似乎是异步lambda。 我明白,如果我这样写:

var forms = await await _dispatcher.InvokeAsync(() => LoadForm(browser, form.Url));

然后LoadForm的返回类型是Task<T>InvokeAsync返回Task<lambda return type>所以它确实是Task<Task<T>> 但是当一个Task方法await 'ed'时,是不是“从” Task “解开”实际的返回类型? 所以,如果我写:

var forms = await LoadForm(browser, form.Url);

forms将是T ,而不是Task<T> 为什么在异步lambda中不会发生同样的情况?

你已经回答了自己的问题。 InvokeAsync返回一个Task<T> ,其中T是提供给它的Func<TResult>委托的返回类型。 当您使用异步lambda时,您不再处理Func<TResult> ,而是处理Func<Task<TResult>>

您认为解包应该自动发生的原因可能是由于过去使用Task.Run 但应该注意的是, Task.Run有一个重载接受一个Func<T>并返回一个Task<T> ,一个重载接受一个Func<Task<T>>仍然返回Task<T> ,所以你把这个在封面后面发生的事情解开是理所当然的。 但是,这不适用于您的情况。

在这方面, Dispatcher.InvokeAsync类似于Task.Factory.StartNew 它没有专门处理Func<Task<TResult>>的重载,所以你不得不“手动”解包。

InvokeAsync是,考虑一下你的场景中是否真的需要InvokeAsync 除了调度程序线程超负荷工作之外,它不会给你太多。 它返回的Task通常会立即完成(无需等待async lambda创建的Task ),只需再给你一层包装来处理。 LoadForm已经是async所以你也可以使用Dispatcher.Invoke ,它将在正确的SynchronizationContext上触发你的async lambda,并最终返回你想要等待的任务,或者,如果你知道你的LoadForm将始终被调用对于SynchronizationContext (也就是说,在UI线程上),完全省略调度程序调用,让async/await做它的事情。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM