45

At the end of a Task-returning async method, if I call another async method, I could either await it or return its task. Which are the consequences of each?

    Task FooAsync()
    {
        return BazAsync();  // Option A
    }

    async Task BarAsync()
    {
        await BazAsync(); // Option B
    }
Jay Bazuzi
  • 45,157
  • 15
  • 111
  • 168
  • 4
    Doing this can be dangerous if you combine it with `using`: `using (something) { return BazAsync(); }` and `using (something) { await BazAsync(); }` behave very differently. – svick Jul 26 '13 at 18:17
  • Linking a similar question: http://stackoverflow.com/q/21033150/1768303 – noseratio May 08 '14 at 10:02
  • 5
    I wrote a blog post on the [advantages and pitfalls of eliding `async`/`await`](http://blog.stephencleary.com/2016/12/eliding-async-await.html). – Stephen Cleary Mar 10 '17 at 13:43

2 Answers2

36

You can't return the task if the method itself is declared to be async - so this won't work, for example:

async Task BarAsync()
{
    return BazAsync(); // Invalid!
}

That would require a return type of Task<Task>.

If your method is just doing a small amount of work and then calling just one async method, then your first option is fine, and means there's one fewer task involved. You should be aware that any exceptions thrown within your synchronous method will be delivered synchronously though - indeed, this is how I prefer to handle argument validation.

It's also a common pattern for implementing overloading e.g. by cancellation token.

Just be aware that if you need to change to await something else, you'll need to make it an async method instead. For example:

// Version 1:
Task BarAsync()
{
    // No need to gronkle yet...
    return BazAsync();
}

// Oops, for version 2 I need to do some more work...
async Task BarAsync()
{
    int gronkle = await GronkleAsync();
    // Do something with gronkle

    // Now we have to await BazAsync as we're now in an async method
    await BazAsync();
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    `If your method is just doing a small amount of work and then calling just one async method` In particular, this is a common pattern for overloading `async` methods (e.g., `BarAsync()` and `BarAsync(CancellationToken)`). – Stephen Cleary Jul 26 '13 at 17:09
  • 2
    @StephenCleary: Indeed - and likewise validating synchronously followed by returning the "real" async task. Will edit to indicate that. – Jon Skeet Jul 26 '13 at 17:12
  • @JonSkeet, sorry for reviving this after 3 years, but question - whenever I see code that doesn't have an `await` and just returns the `Task`, if there is an exception during that task it sometimes seems to 'disappear', even if the caller is awaiting the task. Would this be related to your comment about the exceptions being thrown synchronously? – Cody Aug 11 '16 at 14:32
  • @Cody: No, the exception doesn't disappear. I suggest you ask a new question showing your situation in more detail. – Jon Skeet Aug 11 '16 at 22:06
2

Check out this link where it is described: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

async Task<int> TaskOfTResult_MethodAsync()
{
    int hours;
    // . . .
    // The body of the method should contain one or more await expressions.

    // Return statement specifies an integer result.
    return hours;
}

    // Calls to TaskOfTResult_MethodAsync from another async method.
private async void CallTaskTButton_Click(object sender, RoutedEventArgs e)
{
    Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
    int intResult = await returnedTaskTResult;
    // or, in a single statement
    //int intResult = await TaskOfTResult_MethodAsync();
}






// Signature specifies Task
async Task Task_MethodAsync()
{
    // . . .
    // The body of the method should contain one or more await expressions.

    // The method has no return statement.  
}

    // Calls to Task_MethodAsync from another async method.
private async void CallTaskButton_Click(object sender, RoutedEventArgs e)
{
    Task returnedTask = Task_MethodAsync();
    await returnedTask;
    // or, in a single statement
    //await Task_MethodAsync();
}
Kees
  • 1,408
  • 1
  • 15
  • 27