在promise类型的任务中不能调用Start.异常即将到来

本文关键字:调用 Start 异常 即将到来 不能 promise 类型 任务 | 更新日期: 2023-09-27 17:51:08

我正在创建一个简单的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:

Start不能在promise类型的任务上调用。

有谁能告诉我为什么是这样的吗?

在promise类型的任务中不能调用Start.异常即将到来

你得到这个错误,因为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编写这些方法会更加困难和混乱。它还极大地简化了错误处理,省去了大量的样板代码。