我正在创建一个简单的wpf桌面应用程序。 UI只有一个按钮和.cs文件中的代码,如。
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public void FunctionA()
{
Task.Delay(5000).Start();
MessageBox.Show("Waiting Complete");
}
但令人惊讶的是,Task.Delay(5000).Start();
行正在抛出InvalidOperationException
:
启动可能不会在promise样式的任务上调用。
任何人都可以帮忙为什么会这样吗?
答案 0 :(得分:152)
您收到该错误,因为Task
类已经启动了该任务,然后再将其提供给您。你应该只通过调用它的构造函数来调用你创建的任务上的Start
,除非你有一个令人信服的理由在你创建任务时没有启动任务,否则你不应该这样做;如果您希望立即开始,则应使用Task.Run
或Task.Factory.StartNew
创建并开始新的Task
。
所以,现在我们知道要摆脱那个讨厌的Start
。您将运行您的代码并发现消息框会立即显示,而不是在5秒后显示,具体是什么?
好吧,Task.Delay
只是给你一个将在5秒内完成的任务。它不会停止执行该线程5秒钟。你想要做的是拥有一些在该任务完成后执行的代码。这是ContinueWith
的用途。它允许您在完成给定任务后运行一些代码:
public void FunctionA()
{
Task.Delay(5000)
.ContinueWith(t =>
{
MessageBox.Show("Waiting Complete");
});
}
这将按预期运作。
我们还可以利用C#5.0 await
关键字更轻松地添加续集:
public async Task FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}
虽然对此处发生的事情的完整解释超出了本问题的范围,但最终结果是一种行为与前一种方法非常相似;它会在你调用方法后5秒显示一个消息框,但在这两种情况下,方法本身将立即返回[几乎]。也就是说,await
非常强大,并且允许我们编写看似简单明了的方法,但直接使用ContinueWith
编写会更加困难和麻烦。它还大大简化了错误处理的处理,取出了很多样板代码。
答案 1 :(得分:1)
试试这个。
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public async void FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}
答案 2 :(得分:-5)
正如Servy所说,任务已经开始,所以你剩下要做的就是等待它(.Wait()):
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public void FunctionA()
{
Task.Delay(5000).Wait();
MessageBox.Show("Waiting Complete");
}