1

If I write a method that is just wrapping an async method such as this:

public async Task WrapMethodAsync()
{
    using(var smtpClient = new SmtpClient())
    {
        await smtpClient.SendMailAysnc(new MailMessage());
    }
}

Is that the same as doing the following:

public Task WrapMethodAsync()
{
    using(var smtpClient = new SmtpClient())
    {
        return smtpClient.SendMailAysnc(new MailMessage());
    }
}

Or is the latter not actually running asynchronously?

i3arnon
  • 113,022
  • 33
  • 324
  • 344
Dismissile
  • 32,564
  • 38
  • 174
  • 263
  • 2
    I'm sure this is a duplicate. The answer is "mostly" - the difference being that if an exception is thrown by the `SmtpClient` constructor (or the `MailMessage` constructor, or the start of the `SendMailAsync` method), in the first case you'll get a faulted task; in the second case you'll get an exception straight away. – Jon Skeet Mar 25 '15 at 19:48
  • It's probably a duplicate, but for the life of me I didn't know what to search by. – Dismissile Mar 25 '15 at 19:51
  • Understood. Hopefully someone else will find one. – Jon Skeet Mar 25 '15 at 19:51
  • Search for "C# await tutorial". This is so basic that you must be able to answer this yourself. If you don't know the answer to this question using async programming is quite dangerous. – usr Mar 25 '15 at 19:51
  • 1
    @JonSkeet The semantics of disposing the client are far more important than the exception handling semantics. – Servy Mar 25 '15 at 19:51
  • @Servy: Eek, you're absolutely right - missed that entirely! – Jon Skeet Mar 25 '15 at 19:57

2 Answers2

7

In this exact scenario the two cases are extremely different because of the using scope.

In the first case you wait (asynchronously) for the SendMailAysnc operation to complete before disposing of the client while in the other case you don't so you would dispose of the client while the operation is still running.

In the general case where there isn't a difference in the general behavior. For example this:

public async Task Run()
{
    throw new Exception("stored");
    await Task.Delay(-1);
}

VS this:

public Task Run()
{
    throw new Exception("thrown");
    return Task.Delay(-1);
}

The difference is that the async method has a slight overhead of the whole async mechanism (including a state machine) while the non-async task-returning method has a different exception semantics as exceptions are thrown directly and not stored in the returned task.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
4

The first snippet disposes of the client after the mail is sent, the latter disposes of the client after it starts sending the mail, but before it has finished. Assuming the client isn't supposed to be disposed while it is sending messages, it means that the first solution is very problematic.

Additionally, the error handling semantics are different; exceptions in constructing the Task in the first snippet will result in the method throwing an exception, whereas in the second snippet they result in the return task being marked as Faulted with the appropriate exception set.

Servy
  • 202,030
  • 26
  • 332
  • 449