What is the correct way to mark async method as not implemented/not supported or invalid operation. For the simplicity I would use only NotImplementedException
in examples, but the question applies to the NotSupportedException
and InvalidOperationException
as well.
In a sync way one would simple throw the exception:
public override void X() {
throw new NotImplementedException();
}
What would be the equivalent of this code in async world?
/* 1 */ public override Task XAsync() {
throw new NotImplementedException();
}
Or
/* 2 */ public override Task XAsync() {
return Task.FromException(new NotImplementedException());
}
What are the complications of these approaches? Is there any better method?
To avoid the "Nah, you don't need a method to be async here"/"It's not async" I would say that the method implements some interface or abstract class.
Some methods which I'm not considering:
/* 3 */ public async override Task XAsync() { // here is an CS1998 warning
throw new NotImplementedException();
}
The compiler would just generate the useless state machine, which is semantically equivalent to 2
/* 4 */ public async override Task XAsync() {
await Task.Yield();
throw new NotImplementedException();
}
This is the same as 3, but with added await on Task.Yeild();
Async void methods can wreak havoc if the caller isn't expecting them to be async. When the return type is Task, the caller knows it's dealing with a future operation; when the return type is void, the caller might assume the method is complete by the time it returns.
Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object.
Solution A If you have a simple asynchronous method that doesn't need to synchronize back to its context, then you can use Task. WaitAndUnwrapException : var task = MyAsyncMethod(); var result = task. WaitAndUnwrapException();
I'm going to go out on a limb and say "it doesn't matter."
Boneheaded exceptions can be thrown directly (throw
) or placed on the returned task (Task.FromException
). Since they're boneheaded exceptions, they shouldn't ever be caught anyway, so it doesn't matter where they are thrown.
When calling a method that returns a Task
, some parts of it are executed synchronously (even if the implementing method is defined as async
and has await
calls in it.. until the first away, everything is synchronous by default).
So the outcome is the same for all options: throw immediately or return a Task that is already completed with an exception (only behaves the same if you await the call immediately) or mark a method async
(which would expect you to have await
calls but let's add it for completeness).
I'd go for throwing immediately because returning a Task may indicate that you "have started work" and the caller isn't required to await a Task so if the caller doesn't really care about when your Task
completes (it doesn't even have a return value), the fact that the method isn't implemented won't show up.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With