Start peut ne pas être appelé sur une tâche de style promise. exception est à venir

Je crée une application de bureau WPF simple. L'interface utilisateur a juste un bouton et un code .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 line {[1] } lance un InvalidOperationException:

Start peut ne pas être appelé sur une tâche de style promise.

Quelqu'un peut-il aider pourquoi c'est comme ça?

90
demandé sur croxy 2013-01-09 11:38:19

3 réponses

Vous obtenez cette erreur parce que la classe Task a déjà commencé la tâche avant de vous la donner. Vous ne devriez appeler Start que sur une tâche que vous créez en appelant son constructeur, et 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 qu'elle commence tout de suite, vous devez utiliser Task.Run ou Task.Factory.StartNew pour créer et démarrer un nouveau Task.

Donc, maintenant, nous savons simplement se débarrasser de ce fichus Start. Vous exécuterez votre code et trouver que la boîte de message est montré tout de suite, pas 5 secondes plus tard, qu'est-ce qui?

Eh bien, Task.Delay Vous donne juste une tâche qui sera terminée en 5 secondes. Il n'arrête pas l'exécution du thread pendant 5 secondes. Ce que vous voulez faire, c'est avoir du code qui est exécuté après la fin de cette tâche. C'est à ça que sert ContinueWith. Il vous permet d'exécuter du code après une tâche donnée:

public void FunctionA()
{
    Task.Delay(5000)
    .ContinueWith(t => 
    {
        MessageBox.Show("Waiting Complete");
    });
}

Cela se comportera comme prévu.

Nous pourrions également tirer parti de C# 5.0 await mot-clé 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 très similaire à la méthode précédente; elle affichera une boîte de message 5 secondes après avoir appelé la méthode, mais la méthode elle-même retournera [presque] immédiatement dans les deux cas. Cela dit, await est très puissant, et permet d'écrire des méthodes qui semblent simples et directes, mais qui serait beaucoup plus difficile et messier à écrire en utilisant ContinueWith directement. Il simplifie également grandement la gestion des erreurs, en retirant beaucoup de code standard.

134
répondu Servy 2016-03-26 23:37:07

Essayez ceci.

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

public async void FunctionA()
{
    await Task.Delay(5000);
    MessageBox.Show("Waiting Complete");
}
1
répondu Mathias Lykkegaard Lorenzen 2013-03-01 21:24:17

Comme L'a dit Servy, la tâche a déjà commencé, il ne vous reste donc plus qu'à l'attendre (.Wait ()):

private void Button_Click_2(object sender, RoutedEventArgs e)
{
    FunctionA();
}
public void FunctionA()
{
    Task.Delay(5000).Wait();
    MessageBox.Show("Waiting Complete");
}
-5
répondu Sergiu 2015-01-20 07:37:07