Double await when invoke async lambda via Dispatcher

async-await, c#, dispatcher, task-parallel-library, wpf

Solution

You've answered your own question. `InvokeAsync` returns a `Task<T>` where `T` is the return type of the `Func<TResult>` delegate supplied to it. When you use an async lambda, you are no longer dealing with `Func<TResult>`, but instead `Func<Task<TResult>>`.

The reason you think that unwrapping should happen automatically is probably due to using `Task.Run` in the past. It should be noted, however, that `Task.Run` has an overload which accepts a `Func<T>` and returns a `Task<T>`, and an overload which accepts a `Func<Task<T>>`, and still returns `Task<T>`, so you take this unwrapping which is happening for you behind the covers for granted. This, however, does not apply in your case.

`Dispatcher.InvokeAsync` is similar to `Task.Factory.StartNew` in this regard. It does not have an overload which would specifically deal with `Func<Task<TResult>>`, so you're stuck with unwrapping "manually".

Thing is, think about whether you really need `InvokeAsync` in your scenario. It won't give you much outside of scenarios where the dispatcher thread is overloaded with work. The `Task` which it returns will generally complete immediately (without awaiting the `Task` created by your `async` lambda) and just give you one more layer of wrapping to deal with. `LoadForm` is already `async` so you might as well just use `Dispatcher.Invoke` which will fire off your `async` lambda on the correct `SynchronizationContext` and ultimately return the task that you want to await, or, if you know that your `LoadForm` will always be called with the right `SynchronizationContext` (that is, on the UI thread), omit the dispatcher calls altogether and just let `async/await` do its thing.

Problem

``` private async Task<T> LoadForm(WebControlAsync browser, Uri url) { ... } var forms = await await _dispatcher.InvokeAsync(async () => await LoadForm(browser, form.Url)); ``` I don't understand why I have to use two `await`'s here to get `T` in `forms`? So it looks as `InvokeAsync` returns `Task<Task<T>>`. But when I invoke synchronous method like this: ``` var forms = await _dispatcher.InvokeAsync(() => FillForm(forms, url)); ``` it requires only single `await`. So the cause seems to be async lambda. I understand that if I write it this way: ``` var forms = await await _dispatcher.InvokeAsync(() => LoadForm(browser, form.Url)); ``` then the return type of `LoadForm` is `Task<T>` and `InvokeAsync` returns `Task<lambda return type>` so it indeed would be `Task<Task<T>>`. But when a `Task` method is `await`'ed, isn't it "unwraps" the actual return type from `Task`? So if I write: ``` var forms = await LoadForm(browser, form.Url); ``` `forms` would be `T`, not `Task<T>`. Why the same isn't happen in async lambda?

Original source