Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not implemented/supported/invalid operation async method

Tags:

c#

async-await

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();

like image 564
hazzik Avatar asked May 04 '17 20:05

hazzik


People also ask

Why you shouldn't use async void?

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.

What happens if an exception is thrown within an asynchronous method?

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.

Can we call asynchronous method from another synchronous method?

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();


2 Answers

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.

like image 153
Stephen Cleary Avatar answered Oct 07 '22 06:10

Stephen Cleary


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.

like image 40
Martin Ullrich Avatar answered Oct 07 '22 06:10

Martin Ullrich