I have made this mistake a few times now so I thought I would try to cement it in to my memory by writing a post about it!
I had a case where I wanted to separate the task creation from the task run in one of my previous posts and I used code that looked like this ...
static async Task FireAndForget()
{
// Warning: Do not do this ...
Task task = new Task(async () =>
{
Console.WriteLine("Going to sleep ...");
await Task.Delay(1000);
Console.WriteLine("... Woke up");
});
task.Start();
await task;
}
static async Task Main(string[] args)
{
await FireAndForget();
Console.WriteLine("Run complete");
Console.ReadKey();
}
Going to sleep ...
Run complete
... Woke up
Initially I expected the "... Woke up" message to be output before the "Run complete" message. But then I remembered that the signature for the Task constructor is ...
public Task (Action action);
This means I am awaiting a task that is executing an action. Action returns an async void so when the action is executed, it will not actually await the completion of the Task.Delay.
What I actually needed to use was Func that returns a Task ...
static async Task FireAndAwaitAsync()
{
var funcTask = new Func<Task>(async () =>
{
Console.WriteLine("Going to sleep ...");
await Task.Delay(1000);
Console.WriteLine("... Woke up");
});
Task task = funcTask.Invoke();
await task;
}
static async Task Main(string[] args)
{
await FireAndAwaitAsync();
Console.WriteLine($"{DateTime.Now} Run complete");
Console.ReadKey();
}
Which outputs ...
Going to sleep ...
... Woke up
Run complete
Generally you don't need to separate out task creation from running the task so this is not usually an issue. Now to go back over my previous posts and make sure I fix this error.
Top comments (1)
Great post!I wish all devs would post this way!Thank you for the insight, async is tough to comprehend!