Ich erstelle eine einfache Wpf-Desktop-Anwendung. Ich habe nur eine Schaltfläche und Code in .cs-Datei wie.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public void FunctionA()
{
Task.Delay(5000).Start();
MessageBox.Show("Waiting Complete");
}
Aber überraschenderweise wirft Zeile Task.Delay(5000).Start();
ein InvalidOperationException
:
Start darf nicht für eine versprochene Aufgabe aufgerufen werden.
Kann jemand helfen, warum es so ist?
Sie erhalten diesen Fehler, weil die Klasse Task
die Aufgabe bereits gestartet hat, bevor sie Ihnen übergeben wurde. Sie sollten Start
immer nur für eine Aufgabe aufrufen, die Sie durch Aufrufen ihres Konstruktors erstellen, und Sie sollten dies nicht einmal tun, es sei denn, Sie haben einen zwingenden Grund, die Aufgabe beim Erstellen nicht zu starten. Wenn Sie möchten, dass es sofort startet, sollten Sie Task.Run
oder Task.Factory.StartNew
, um ein neues Task
zu erstellen und zu starten.
Jetzt wissen wir also, dass wir diesen lästigen Start
loswerden müssen. Sie werden Ihren Code ausführen und feststellen, dass das Meldungsfeld sofort und nicht 5 Sekunden später angezeigt wird. Was ist damit los?
Gut, Task.Delay
gibt dir nur eine Aufgabe, die in 5 Sekunden erledigt ist. Die Ausführung des Threads wird nicht für 5 Sekunden gestoppt. Was Sie tun möchten, ist ein Code, der ausgeführt wird, nachdem diese Aufgabe abgeschlossen ist. Dafür ist ContinueWith
. Hiermit können Sie Code ausführen, nachdem eine bestimmte Aufgabe erledigt ist:
public void FunctionA()
{
Task.Delay(5000)
.ContinueWith(t =>
{
MessageBox.Show("Waiting Complete");
});
}
Dies wird sich wie erwartet verhalten.
Wir könnten auch das Schlüsselwort await
von C # 5.0 verwenden, um Fortsetzungen einfacher hinzuzufügen:
public async Task FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}
Eine vollständige Erklärung dessen, was hier vor sich geht, würde den Rahmen dieser Frage sprengen, doch das Endergebnis ist eine Methode, die sich der vorherigen Methode sehr ähnlich verhält. 5 Sekunden nach dem Aufrufen der Methode wird ein Meldungsfeld angezeigt, die Methode selbst kehrt jedoch in beiden Fällen [fast] sofort zurück. Das heißt, await
ist sehr mächtig und ermöglicht es uns, Methoden zu schreiben, die einfach und unkompliziert erscheinen, aber mit ContinueWith
direkt viel schwieriger und unübersichtlicher zu schreiben wären. Es vereinfacht auch den Umgang mit der Fehlerbehandlung erheblich und spart eine Menge Code.
Versuche dies.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public async void FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}