I would like to ask to redefine the scope for S4457.
According the description, the intention is to ensure exceptions are thrown in the synchronous part of an asynchronous method.
So, why complaining about exceptions thrown before the first await?
I would like to see that argument checks at the beginning of a method should be compliant.
Exceptions after first await should be non-compliant.
public async Task MyMethodAsync(Order order)
{
ArgumentNullException.ThrowIfNull(order); // compliant
var result = await AnotherAsync(); // here starts the asynchronous part
if (result.State == foo)
{
throw new InvalidOperationException("bar"); // non-compliant
}
}
When marking a method asynchronous, the compiler transforms the method into a state machine.
It takes the whole body, making no difference between what could be synchronous and what is not, so in a sense, an async method does not contain any synchronous part.
As mentioned in the rule description, when a method is wrapped by the compiler as such, there is no guarantee it will be executed right away. As a consequence, your parameter validation exception might be raised at an unexpected time. Thus, S4457 complains.
In other words, it is expected to raise in your scenario.
S4457 is specifically about argument validation in an asynchronous method. Other exceptions are completely valid in an asynchronous context.
If you want to know more about how async/await works, I suggest this blog post: How Async/Await Really Works in C#, especially the paragraph about the transformation done by the compiler.