Ale*_*bin 3 c# wpf dispatcher task-parallel-library async-await
private async Task<T> LoadForm(WebControlAsync browser, Uri url)
{ ... }
var forms = await await _dispatcher.InvokeAsync(async () => await LoadForm(browser, form.Url));
Run Code Online (Sandbox Code Playgroud)
我不明白为什么我必须使用两个await的在这里得到T的forms?所以它看起来像InvokeAsync回报Task<Task<T>>.但是当我调用这样的同步方法时:
var forms = await _dispatcher.InvokeAsync(() => FillForm(forms, url));
Run Code Online (Sandbox Code Playgroud)
它只需要单身await.所以原因似乎是异步lambda.我明白,如果我这样写:
var forms = await await _dispatcher.InvokeAsync(() => LoadForm(browser, form.Url));
Run Code Online (Sandbox Code Playgroud)
然后返回类型LoadForm是Task<T>和InvokeAsync返回Task<lambda return type>所以它确实会Task<Task<T>>.但是当一个Task方法被await编辑时,是不是"从"开始实际返回类型Task?所以,如果我写:
var forms = await LoadForm(browser, form.Url);
Run Code Online (Sandbox Code Playgroud)
forms会T,不是Task<T>.为什么在异步lambda中不会发生同样的情况?
你已经回答了自己的问题.InvokeAsync返回一个Task<T>where,它T是Func<TResult>提供给它的委托的返回类型.当您使用异步lambda时,您不再处理Func<TResult>,而是处理Func<Task<TResult>>.
您认为展开应该自动发生的原因可能是由于Task.Run过去使用.然而,应该注意的是,它Task.Run有一个接受a Func<T>并且返回a Task<T>的重载,以及一个接受a的重载Func<Task<T>>,并且仍然返回Task<T>,所以你把这个在封面后面发生的解开是理所当然的.但是,这不适用于您的情况.
Dispatcher.InvokeAsyncTask.Factory.StartNew在这方面类似.它没有专门处理的过载Func<Task<TResult>>,所以你不得不"手动"展开.
事情是,考虑一下InvokeAsync你的场景中是否真的需要.除了调度程序线程超负荷工作之外,它不会给你太多.在Task其返回通常会立即完成(不等待Task你创建async拉姆达),只是给你包装处理的又一个层.LoadForm已经是async这样你可能只是使用Dispatcher.Invoke哪个会async在正确的情况下触发你的lambda SynchronizationContext并最终返回你想要等待的任务,或者,如果你知道你的LoadForm总是会被正确调用SynchronizationContext(也就是说,在UI上)线程),完全省略调度程序调用,只是让它async/await做的事情.