If you literally have the code shown, then you should prefer the return FrobnicateAsync()
version - it avoids an extra layer of state machine abstraction and is simply more efficient.
If you have additional things - in particular any finally
(including using
) code that surrounds the return
, then you must be sure to use the await
version so that the finally
code doesn't happen until after the async
task has completed.
If in doubt, use the async
/await
version.
The good news is: it doesn't impact the signature (so is not a breaking change) to switch between them, so you can implement it the more efficient way now, and change to async
/await
if you find that you need to add a using
block later.
As an additional thought: if you usually expect it to be completed synchronously, you can be more subtle:
Task FrobAndFrobnicateAsync()
{
async Task Awaited(Task t) => await t;
Frob();
var task = FrobnicateAsync();
// in .NET vFuture there will be a task.IsCompletedSuccessfully
return task.State == TaskState.RanToCompletion ? task : Awaited(task);
}
This avoids the state machine when not needed.