Why should a void method be async to be able to await?
Asynchronous methods must be marked async
. The async
and await
keywords are paired together, primarily for backwards-compatibility reasons; await
was a valid identifier (not a keyword), so when it was added to the language, they also added the async
keyword.
Alternatively, they could have gone with a multi-word keyword for await
, such as await for
. However, the language design team decided to go with the pairing, since it clearly and explicitly marks all async
methods - it's easier for both compilers and humans to parse.
I have a blog post on the subject, with links to Eric Lippert's definitive blog post as well as discussions in blog comments, Channel9 forums, MSDN forums, and of course right here on Stack Overflow.
Note that the natural return type of an async
method without a result value is Task
, not void
. void
is an unnatural return type for async
methods. So your default reaction when seeing the "await operator must be within an async method" error should be to mark it async
and change the return type from void
to Task
:
public async Task someOperationAsync()
{
//dostuff
var res = await someOtherOperationAsync();
//do some other stuff that needs res.
}
This follows one of the best practices in my MSDN article on the subject: avoid async void
. async void
was allowed by the language designers for event handlers (or code that is logically an event handler, like ICommand.Execute
); any other usage is going to cause problems.
How(and why) can I avoid returning a void on these async methods?
Constructor are meant to bring an object to it's fully constructed structure once initialized. On the other hand, async methods and constructors don't play well together, as a constructor is inherintly synchronous.
The way to get around this problem is usually to expose an initialization method for the type, which is itself async. Now, you let the caller initialize the object fully. Note this will require you to monitor the actual initialization of the method.
Async shines when you need scale. If you don't expect this to be an IO bottleneck in your application, perhaps consider using synchronous methods instead. This will give you the benefit of actually fully initializing your object once the constructor finishes execution. Although, I don't think I would initiate a call to a database via a constructor anyway:
public async Task InitializeAsync()
{
LoadFromLocal();
await AttemptDatabaseLoadAsync();
}
public async Task AttemptDatabaseLoadAsyncAsync()
{
while(ConnectionAttempts < MAX_CONNECTION_ATTEMPTS)
{
Task<bool> Attempt = TryLoad ();
bool success = await Attempt;
if (success)
{
//call func to load data into program memory proper
}
else
{
ConnectionAttempts++;
}
}
}
And call it:
var dataLoader = new DataLoader();
await dataLoader.InitializeAsync();
One line fire and forget: void vs. async void + await
My understanding is that adding async void and await in this case would just be useless overhead.
No.
If Handler
returned a Task
, then that would be true and eliding async
/await
would be fine; the code without async
/await
would just return the Task
directly instead of "unwrapping" it with await
and "wrapping" it back into a Task
with async
.
However, that's not the case here; Handler
returns void
, so the code without async
/await
will just ignore the returned Task
, which is wrong the vast majority of the time (hence the compiler warning). Specifically, ignoring the Task
will ignore any exceptions from that Task
. It's also not possible for your code to know when an ignored Task
has completed, but presumably that's acceptable since your handler is returning void
.
There is a "registration" that async void
methods do so that the framework is aware there is a task still in progress, so the framework knows when it's safe to shut down. The only .NET provided framework that actually cares about that is ASP.NET pre-Core; all other .NET-provided frameworks (including all UI frameworks) ignore that "registration".
How to use async/await on void methods in ASP.NET Core?
You can write async void methods but these cannot be awaited:
public static class Program
{
public static async Task Main()
{
const int mainDelayInMs = 500;
AsyncVoidMethod();
await Task.Delay(mainDelayInMs);
Console.WriteLine($"end of {nameof(Main)}");
}
static async void AsyncVoidMethod()
{
await Task.Delay(1000);
Console.WriteLine($"end of {nameof(AsyncVoidMethod)}");
}
}
As you can see AsyncVoidMethod is async but I cannot write await AsyncVoidMethod();
.
Async void methods should (most of the time) not be used as you cannot wait for completion of the task and any exception thrown may not be handled(and so it can crash your application): Why exactly is void async bad?
async/await - when to return a Task vs void?
Normally, you would want to return a
Task
. The main exception should be when you need to have avoid
return type (for events). If there's no reason to disallow having the callerawait
your task, why disallow it?async
methods that returnvoid
are special in another aspect: they represent top-level async operations, and have additional rules that come into play when your task returns an exception. The easiest way is to show the difference is with an example:
static async void f()
{
await h();
}
static async Task g()
{
await h();
}
static async Task h()
{
throw new NotImplementedException();
}
private void button1_Click(object sender, EventArgs e)
{
f();
}
private void button2_Click(object sender, EventArgs e)
{
g();
}
private void button3_Click(object sender, EventArgs e)
{
GC.Collect();
}
f
's exception is always "observed". An exception that leaves a top-level asynchronous method is simply treated like any other unhandled exception. g
's exception is never observed. When the garbage collector comes to clean up the task, it sees that the task resulted in an exception, and nobody handled the exception. When that happens, the TaskScheduler.UnobservedTaskException
handler runs. You should never let this happen. To use your example,
public static async void AsyncMethod2(int num)
{
await Task.Factory.StartNew(() => Thread.Sleep(num));
}
Yes, use async
and await
here, they make sure your method still works correctly if an exception is thrown.
For more information see: https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
What's the difference between returning void and returning a Task?
SLaks and Killercam's answers are good; I thought I'd just add a bit more context.
Your first question is essentially about what methods can be marked async
.
A method marked as
async
can returnvoid
,Task
orTask<T>
. What are the differences between them?
A Task<T>
returning async method can be awaited, and when the task completes it will proffer up a T.
A Task
returning async method can be awaited, and when the task completes, the continuation of the task is scheduled to run.
A void
returning async method cannot be awaited; it is a "fire and forget" method. It does work asynchronously, and you have no way of telling when it is done. This is more than a little bit weird; as SLaks says, normally you would only do that when making an asynchronous event handler. The event fires, the handler executes; no one is going to "await" the task returned by the event handler because event handlers do not return tasks, and even if they did, what code would use the Task for something? It's usually not user code that transfers control to the handler in the first place.
Your second question, in a comment, is essentially about what can be await
ed:
What kinds of methods can be
await
ed? Can a void-returning method beawait
ed?
No, a void-returning method cannot be awaited. The compiler translates await M()
into a call to M().GetAwaiter()
, where GetAwaiter
might be an instance method or an extension method. The value awaited has to be one for which you can get an awaiter; clearly a void-returning method does not produce a value from which you can get an awaiter.
Task
-returning methods can produce awaitable values. We anticipate that third parties will want to create their own implementations of Task
-like objects that can be awaited, and you will be able to await them. However, you will not be allowed to declare async
methods that return anything but void
, Task
or Task<T>
.
(UPDATE: My last sentence there may be falsified by a future version of C#; there is a proposal to allow return types other than task types for async methods.)
(UPDATE: The feature mentioned above made it in to C# 7.)
Related Topics
How to Get Intptr from Byte[] in C#
Entity Framework Very Slow to Load for First Time After Every Compilation
How to Retrieve Data Annotations from Code? (Programmatically)
Replace Multiple String Elements in C#
C# - Get a List of Files Excluding Those That Are Hidden
What Is the Equivalent of Java's Final in C#
Addbusinessdays and Getbusinessdays
How to Deploy Application with SQL Server Database on Clients
Combination of List<List<Int>>
Why Cannot C# Generics Derive from One of the Generic Type Parameters Like They Can in C++ Templates
The Need for Volatile Modifier in Double Checked Locking in .Net
What Is the Equivalent of Memset in C#
Detect Webbrowser Complete Page Loading
Invalid Attempt to Read When No Data Is Present
Filenotfoundexception in Applicationsettingsbase
How to Determine If a Type Implements an Interface with C# Reflection