30

I have an async method:

public async Task<UserLoginExResult> LoginExAsync(CustomTable exRequest, string language, bool throwEx = true)
{
    UserLoginExResult result = await UserService.LoginExAsync(UserGroup, language, TimezoneOffset, GetDeviceInfo(), GetLoginProperties(), exRequest);

    ProcessLoginResult(result, false, throwEx);

    return result;
}

And an overload:

public Task<UserLoginExResult> LoginExAsync(CustomTable exRequest, bool throwEx = true)
{
    return LoginExAsync(exRequest, Language.ID, throwEx);
}

I'm not sure if I should mark the overloaded one (the one with fewer parameters) as async and use await? I guess I should not but can you tell me what whould happen if I would do that? I'm quite lost in here and not really sure what Task it would wait for? Would it create an extra Task or await doesn't create a new Task?

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
JakubRi
  • 819
  • 9
  • 11

4 Answers4

27

No, there's little benefit in using an async method when it's just going to wrap and unwrap an existing one. It's fine to just have a "normal" method here, delegating to the "real" async method.

(They're not quite the same - for example, if the UserService.LoginExAsync method throws an exception rather than returning a failed task, the async/await version will just return a failed task, whereas the other version will also throw immediately.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • But is there any harm in adding it? What is the cost of the overhead? Or does the compiler optimize it away? – Matt Johnson-Pint Jan 09 '15 at 23:02
  • @Matt: The cost is that of setting up a trivial state machine, basically. It will also change how any exceptions thrown when creating the task get propagated, so they're not 100% equivalent. But the compiler definitely doesn't optimize one to the other. – Jon Skeet Jan 09 '15 at 23:06
  • Thanks. You helped me settle an argument before I even had to have it. :) – Matt Johnson-Pint Jan 09 '15 at 23:07
  • Actually, I found a case where apparently [it does matter](http://stackoverflow.com/q/28053323/634824). Any insight would be appreciated! – Matt Johnson-Pint Jan 20 '15 at 19:10
  • @MattJohnson: I've modified my description to indicate one difference, though I'm not sure it's relevant in your case. Will look at that now. – Jon Skeet Jan 20 '15 at 19:13
11

The async keyword only enables the await keyword. In your case, you can return the Task directly, so there's no need for the async keyword. async would only add overhead without adding any value.

For more information, see Stephen Toub's Zen of Async talk. He addresses this situation directly.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
5

It would really only be worth doing if you were doing additional work in your overload, e.g.

public async Task<UserLoginExResult> LoginExAsync(CustomTable exRequest, bool throwEx = true)
{
    Task<UserLoginExResult> result = await LoginExAsync(exRequest, Language.ID, throwEx);

    //Do some work here that depends on the result from the task completeion

    return result;
}

But as you are not, it isn't!

Justin Harvey
  • 14,446
  • 2
  • 27
  • 30
2

The overload doesn't need to be marked as async as it doesn't internally await anything, so therefore there's nothing for the compiler to rewrite.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742