Start не может быть вызван для задачи в стиле promise. возникает исключение

#c# #discord.net

#c# #c #-4.0 #.net-4.0

Вопрос:

Я создаю простое настольное приложение wpf. В пользовательском интерфейсе есть только кнопка и код в файле .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.

Может ли кто-нибудь помочь, почему это так?

Ответ №1:

Вы получаете эту ошибку, потому 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 напрямую. Это также значительно упрощает обработку ошибок, удаляя много шаблонного кода.