Analyzer proposal: remove redundant state machine
Call out where an async state machine is redundant:
async Task<string> DoSomethingAsync()
{
return await SomethingElseAsync(); // .ConfigureAwait(bool) might be a suffix
}
So long as SomethingElseAsync() returns the same type as the caller, you can abbreviate to:
Task<string> DoSomethingAsync()
{
return SomethingElseAsync();
}
This is almost equivalent, but it doesn't guarantee exceptions are caught and returned as exceptions, so strictly speaking this is more equivalent:
Task<string> DoSomethingAsync()
{
try
{
return SomethingElseAsync();
}
catch (Exception ex)
{
return Task.FromException(ex);
}
}
Cases that cannot be simplified include;
- more than one await
- The await is not immediately returned (or not the last statement).
- The await appears inside a try block.
- A
using varappears in the method, such that it will be disposed of prior to the returned Task being completed.
Probably should offer 2 code fixes, with an additional comment around the try-catch for the more complex code fix?
I generally make this change manually and would appreciate the analyzer, but we should be aware that it changes the debugging experience by removing DoSomethingAsync from the call stack when the program is executing a continuation in SomethingElseAsync.
Removing async also disables the compiler warning saying a task should be awaited, so you'll definitely want to make sure that analyzer is working well before suggesting that async get removed.
This is a performance optimization but it causes a change in the stack trace if an exception is thrown.
Check this post from @StephenCleary:
ReSharper extensiosn ReCommended Extension and AsyncConverter suggesting to remove async/await. This is indeed changes the stack trace but it is still a useful analysis.