Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do async methods throw exceptions on call or on await?

Tags:

c#

async-await

When I call an async method and get a task back, will that immediately throw or will it wait until I await the task?

In other words, will this code work? Or will I have to wrap the method call in the try-block as well?

Task task = ThisMethodWillThrow();

try
{
    await task;
}
catch (Exception e)
{
    Console.WriteLine("oops");
}
like image 679
The Hoff Avatar asked Nov 23 '18 11:11

The Hoff


1 Answers

Both are possible. If the method is actually async (i.e. uses the C# async keyword in the declaration), then the C# compiler wraps it up in such a way that it will always reliably throw on the await, but it is important to note that this is not the only way to write a method that can be await-ed, so: if you don't control the method being called (ThisMethodWillThrow) and can't rely on knowledge of the implementation, it would be better for the try to include the initial invoke, as well as the await.

As an example of a method that will throw immediately rather than in the await:

Task ThisMethodWillThrow() { // note that this is **not** "async", but is awaitable
    if (thingsAreBad) throw new SomeException();
    return SomeInnerMethod();
}
async Task SomeInnerMethod() { ... }

It might be tempting to think "well, just make all awaitable methods async, to avoid this" - like:

async Task ThisMethodWillThrowToo() { // note that this is "async"
    if (thingsAreBad) throw new SomeException();
    await SomeInnerMethod();
}

However: there are scenarios where the async machinery is a very measurable performance overhead in the "often sync, sometimes async" case - and so a common optimization in performance critical awaitable code (IO/network code, for example) is to actively avoid the async machinery unless we know that we're actually falling into the asynchronous path.

like image 51
Marc Gravell Avatar answered Oct 15 '22 02:10

Marc Gravell