C# 不能在承诺风格的任务上调用 Start。异常来了

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14230372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:06:22  来源:igfitidea点击:

Start may not be called on a promise-style task. exception is coming

c#c#-4.0.net-4.0

提问by D J

I am creating a simple wpf desktop application. UI have just a button and code in .cs file like.

我正在创建一个简单的 wpf 桌面应用程序。UI 在 .cs 文件中只有一个按钮和代码。

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:

但令人惊讶的Task.Delay(5000).Start();是,这条线抛出了一个InvalidOperationException

Start may not be called on a promise-style task.

不能在承诺风格的任务上调用 Start。

Can any one help why it is like this?

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

采纳答案by Servy

You are getting that error because the Taskclass already started the task before giving it to you. You should only ever call Starton 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.Runor Task.Factory.StartNewto both create and start a new Task.

您收到该错误是因为Task班级在将任务交给您之前已经开始了该任务。你应该只调用Start你通过调用它的构造函数创建的任务,你甚至不应该这样做,除非你有一个令人信服的理由在你创建它时不启动它;如果您希望它立即开始,您应该使用Task.RunorTask.Factory.StartNew来创建和开始一个新的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?

所以,现在我们知道要摆脱那个讨厌的Start. 您将运行您的代码并发现消息框立即显示,而不是 5 秒后,这是怎么回事?

Well, Task.Delayjust 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 ContinueWithis for. It lets you run some code after a given task is done:

好吧,Task.Delay只是给你一个5秒内完成的任务。它不会停止线程的执行 5 秒。您想要做的是在该任务完成后执行一些代码。这ContinueWith就是为了。它允许您在完成给定任务后运行一些代码:

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 awaitkeyword to add continuations more easily:

我们还可以利用 C# 5.0 的await关键字更轻松地添加延续:

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, awaitis very powerful, and allows us to write methods that seem simple and straightforward, but that would be much harder and messier to write using ContinueWithdirectly. It also greatly simplifies dealing with error handling, taking out a lot of boilerplate code.

虽然对这里发生的事情的完整解释超出了这个问题的范围,但最终结果是一种行为与前一种方法非常相似的方法;它会在您调用该方法 5 秒后显示一个消息框,但在这两种情况下,该方法本身都会[几乎] 立即返回。也就是说,await它非常强大,允许我们编写看似简单直接的方法,但ContinueWith直接使用编写起来会更加困难和混乱。它还极大地简化了错误处理,去掉了大量样板代码。

回答by Mathias Lykkegaard Lorenzen

Try this.

尝试这个。

private void Button_Click_2(object sender, RoutedEventArgs e)
{
    FunctionA();
}

public async void FunctionA()
{
    await Task.Delay(5000);
    MessageBox.Show("Waiting Complete");
}

回答by Sergiu

As Servy said, the task has already started, so all you have left to do is wait for it (.Wait()):

正如Servy所说,任务已经开始,所以你剩下要做的就是等待它(.Wait()):

private void Button_Click_2(object sender, RoutedEventArgs e)
{
    FunctionA();
}
public void FunctionA()
{
    Task.Delay(5000).Wait();
    MessageBox.Show("Waiting Complete");
}