Start may not be called on a promise-style task. exception is coming
I am creating a simple wpf desktop application. UI have just a button and code in .cs file like.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public void FunctionA()
{
Task.Delay(5000).Start();
MessageBox.Show("Waiting Complete");
}
But surprisingly line Task.Delay(5000).Start();
is throwing an InvalidOperationException
:
Start may not be called on a promise-style task.
Can any one help why it is like this?
You are getting that error because the Task
class already started the task before giving it to you. You should only ever call Start
on a task that you create by calling its constructor, and you shouldn't even do that unless you have a compelling reason to not start the task when you create it; if you want it started right away you should use Task.Run
or Task.Factory.StartNew
to both create and start a new Task
.
So, now we know to just get rid of that pesky Start
. You'll run your code and find that the message box is shown right away, not 5 seconds later, what's up with that?
Well, Task.Delay
just gives you a task that will be completed in 5 seconds. It doesn't stop execution of the thread for 5 seconds. What you want to do is have some code that's executed after that task finishes. That's what ContinueWith
is for. It lets you run some code after a given task is done:
public void FunctionA()
{
Task.Delay(5000)
.ContinueWith(t =>
{
MessageBox.Show("Waiting Complete");
});
}
This will behave as expected.
We could also leverage C# 5.0's await
keyword to add continuations more easily:
public async Task FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}
While a full explanation of what's going on here is beyond the scope of this question, the end result is a method that behaves very similar to the previous method; it will show a message box 5 seconds after you call the method, but the method itself will return [almost] right away in both cases. That said, await
is very powerful, and allows us to write methods that seem simple and straightforward, but that would be much harder and messier to write using ContinueWith
directly. It also greatly simplifies dealing with error handling, taking out a lot of boilerplate code.