Just hoping someone could clear up return types when using async
and await
in C#. I understand that you have three return types being Task<T>
, Task
and void
.
From trying to learn about this I have read you should only use void
in special circumstances (Event Handlers) and if you are changing a synchronous method to an async
method then you should change a void
keyword to Task
.
My question is do I need a Task
return type even though the code is completely independent and the result doesn't matter for the continuation? Say for example I use the asynchronous method to push some information to a web service.
I have created a small example to help explain:
private void CallingMethod()
{
AsyncMethod();
AsyncTaskMethod(); // any difference between doing these? (not exc handling)
var task = AsyncTaskMethod(); // should I do anything with this task
// before I continue? Or is it simply
// just to show the user that it's async??
// continue with unrelated code that doesnt require task or any code from above
}
private async void AsyncMethod() // is void okay?
{
await LongRunningMethod();
// do other stuff
}
private async Task AsyncTaskMethod() // or should it be Task?
{
await LongRunningMethod();
// do other stuff
}
private async Task LongRunningMethod()
{
// do long running code
}
My application has a lot of methods like so:
private void BigMethod()
{
DoStuff();
DoMoreStuff();
AsyncMethod(); // is this right? Or should I have the task declaration too?
UnrelatedStuff();
}
private async Task AsyncMethod() // should this return task?
{
var result = await GetUserId();
if (result == null)
return;
MyUserId = result;
}
private async Task<int> GetUserId()
{
// do long running code
return 1;
}
If it's not clear, by all means just say and I'll try to tidy it up a bit. Thanks guys.
EDIT:
private void CallingMethod()
{
AsyncMethod();
}
private async void AsyncMethod()
{
await LongRunningMethod();
}
private async Task LongRunningMethod()
{
await Task.Run(() =>
{
Thread.Sleep(4000);
});
MessageBox.Show("Done!");
}
In response to the first comment, the above CallingMethod()
does not use async/await and it happily sleeps for 4 seconds without locking up the UI thread, then pops up the message box. What's the problem?
You don't have to use
Task
when a method returnsvoid
, but it is indeed preferred, for several reasons:Async methods that return a
Task
(orTask<T>
) have their exceptions put on the returnedTask
, so calling methods can check (when they see fit) whether theTask
was faulted or not.Async void
methods have their exceptions thrown directly on the calling synchronization context, making it nearly (nearly because you can still use global exception handlers, but that's unmaintainable for big applications) impossible to handle exceptions on them on a deterministic manner.You basically can't test any
async void
methods that may throw an exceptionasync void
methods are assumed to be complete when they are run by the caller. This can introduce many problems (in fact, there are many problems with event handlers when you try to convert an existing library to async: go ahead, get a third-party relatively complex winforms library and try to make your event handlers async, you'll see the havoc it creates!).There is no reasonable way to determine when an
async void
method has finished (you could make your ownSynchronizationContext
, but that's something definitely complex)You can't configure an
async void
call (you can't useConfigureAwait
on it), so the continuation context is always the caller's synchronization context.So...
TL;DR: don't use
async void
unless you can't avoid it (that is: with event handlers that expect avoid
signature). There are reasons for it. Useasync Task
if you don't expect a result.You cannot await methods that return
void
and also one of the main reasons is that the caller of a void-returning async method can't catch exceptions that are thrown from the async method. Try that: