C# – Why does C# allow you to make an override async

asyncc

In C#, when you override a method, it is permitted to make the override async when the original method was not. This seems like poor form.

The example that brought me to this was this — I was brought in to assist with a load test problem. At around 500 concurrent users, the login process would break down in a redirect loop. IIS was logging exceptions with the message "An asynchronous module or handler completed while an asynchronous operation was still pending". Some searching led me to think that someone was abusing async void, but my quick searches through the source could find nothing.

Sadly, I was searching for 'async\svoid' (regex search) when I should have been looking for something more like 'async\s[^T]' (assuming Task wasn't fully qualified… you get the point).

What I later found was async override void onActionExecuting(... in a base controller. Clearly that had to be the problem, and it was. Fixing that up (making it synchronous for the moment) resolved the problem.

Back to the question: Why oh why can you mark an override as async when the calling code could never await it?

Best Answer

The async keyword allows the method to use the await syntax within its definition. I can await on any method that returns a Task type regardless of whether it's an async method.

void is a legal (albeit discouraged) return type for an async method, so why wouldn't it be allowed? From the outside, async isn't enabling anything you couldn't do without it. The method you are having trouble with could have been written to behave exactly the same without being async. Its definition just would have been more verbose.

To callers, an async T method is a normal method that returns T (which is limited to void,Task, or Task<A>). That it is an async method is not part of the interface. Notice that the following code is illegal:

interface IFoo {
    async void Bar();
}

It (or similar code in an abstract class) produces the following error message in VS2012:

The 'async' modifier can only be used in methods that have a statement body

If I did intend a method in an interface or parent class to be typically asynchronous, I can't use async to communicate that. If I wanted to implement it with the await syntax, I would need be able to have async override methods (in the parent class case).