可能不会在promise样式的任务上调用Start。例外即将来临

时间:2013-01-09 07:38:19

标签: c# c#-4.0 .net-4.0

我正在创建一个简单的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样式的任务上调用。

任何人都可以帮忙为什么会这样吗?

3 个答案:

答案 0 :(得分:152)

您收到该错误,因为Task类已经启动了该任务,然后再将其提供给您。你应该只通过调用它的构造函数来调用你创建的任务上的Start,除非你有一个令人信服的理由在你创建任务时没有启动任务,否则你不应该这样做;如果您希望立即开始,则应使用Task.RunTask.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");
}