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