Je crée une application de bureau wpf simple. UI ont juste un bouton et un code dans un fichier .cs comme.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public void FunctionA()
{
Task.Delay(5000).Start();
MessageBox.Show("Waiting Complete");
}
Mais étonnamment, la ligne Task.Delay(5000).Start();
jette un InvalidOperationException
:
Start ne peut pas être appelé pour une tâche de type promesse.
Quelqu'un peut-il aider pourquoi c'est comme ça?
Vous obtenez cette erreur car la classe Task
a déjà démarré la tâche avant de vous la transmettre. Vous ne devriez jamais appeler Start
que sur une tâche que vous créez en appelant son constructeur. Vous ne devriez même pas le faire sauf si vous avez une raison impérieuse de ne pas démarrer la tâche lorsque vous la créez; si vous voulez commencer tout de suite, vous devriez utiliser Task.Run
ou Task.Factory.StartNew
pour créer et démarrer un nouveau Task
.
Donc, maintenant, nous savons qu'il faut juste nous débarrasser de cet embêtant Start
. Vous allez exécuter votre code et constater que la boîte de message est affichée tout de suite, pas 5 secondes plus tard, qu'est-ce qui se passe avec ça?
Bien, Task.Delay
vous donne juste une tâche qui sera terminée en 5 secondes. Cela n'arrête pas l'exécution du thread pendant 5 secondes. Ce que vous voulez faire, c'est que du code soit exécuté après la fin de la tâche. C'est ce à quoi ContinueWith
est destiné. Il vous permet d'exécuter du code après qu'une tâche donnée est terminée:
public void FunctionA()
{
Task.Delay(5000)
.ContinueWith(t =>
{
MessageBox.Show("Waiting Complete");
});
}
Cela se comportera comme prévu.
Nous pourrions également utiliser le mot clé await
de C # 5.0 pour ajouter des continuations plus facilement:
public async Task FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}
Bien qu'une explication complète de ce qui se passe ici dépasse le cadre de cette question, le résultat final est une méthode qui se comporte de manière très similaire à la méthode précédente; il affichera une boîte de message 5 secondes après l'appel de la méthode, mais la méthode elle-même renverra [presque] immédiatement dans les deux cas. Cela dit, await
est très puissant et nous permet d’écrire des méthodes qui semblent simples et directes, mais il serait beaucoup plus difficile et plus compliqué d’écrire en utilisant ContinueWith
directement. Cela simplifie également énormément la gestion des erreurs en éliminant beaucoup de code standard.
Essaye ça.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public async void FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}