If you really wanted to you could
var task = SomeMethodAsync();
await task;
var status = task.Status;
But that's pointless because if you're at the line after the await then task has completed, so you just know that's the answer already.
You could catch an exception and then look at the status to distinguish cancellation from faulting, but you can tell that from the exception too, so again it's pointless.
The opposite can be sometimes useful. Say we have:
public async Task XAsync()
{
await YAsync();
await ZAsync();
}
Now let's say that YAsync has a high chance of returning synchronously. Then we could do:
public Task XAsync()
{
Task task = YAsync();
if (task.Status == TaskStatus.RanToCompletion)
return ZAsync();
// Do the awaiting
return XAsync(task);
}
private async Task XAsync(Task task)
{
await task;
await ZAsync();
}
Avoiding the extra allocation and state-machine set-up in this way is only worth it in frequently hit methods, and again only worth it if the odds of the first task repeating synchronously is very high. It also leads to slightly more confusing traces if something goes wrong, but it can have a significant impact.
So testing the status before await has that use. Testing after await tells you something you already know.