2013-01-09 4 views
81

Ich erstelle eine einfache Wpf Desktop-Anwendung. UI haben nur eine Schaltfläche und Code in CS-Datei wie.Start kann bei einer Task im Stil "Versprechen" nicht aufgerufen werden. Ausnahme kommt

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

public void FunctionA() 
{ 
    Task.Delay(5000).Start(); 
    MessageBox.Show("Waiting Complete"); 
} 

Aber überraschend Linie ist Task.Delay(5000).Start(); ein InvalidOperationException werfen:

starten kann nicht auf ein Versprechen Stil Task aufgerufen werden.

Kann jemand helfen, warum es so ist?

Antwort

120

Sie erhalten diesen Fehler, weil die Task schon Klasse die Aufgabe, bevor er es Ihnen gestartet. Sie sollten immer Start für eine Aufgabe aufrufen, die Sie erstellen, indem Sie seinen Konstruktor aufrufen, und Sie sollten das nicht einmal tun, außer Sie haben einen zwingenden Grund, die Aufgabe nicht zu starten, wenn Sie sie erstellen; Wenn Sie möchten, dass es sofort gestartet wird, sollten Sie Task.Run oder Task.Factory.StartNew verwenden, um eine neue Task zu erstellen und zu starten.

So, jetzt wissen wir, nur um diese lästige Start loszuwerden. Sie werden Ihren Code ausführen und feststellen, dass das Meldungsfeld sofort angezeigt wird, nicht 5 Sekunden später, was ist los?

Nun, Task.Delay gibt Ihnen nur eine Aufgabe, die in 5 Sekunden abgeschlossen sein wird. Es stoppt nicht die Ausführung des Threads für 5 Sekunden. Was Sie tun möchten, ist Code, der ausgeführt wird, nachdem die Aufgabe beendet ist. Das ist, was ContinueWith ist für. Damit können Sie nach Abschluss einer bestimmten Aufgabe Code ausführen:

Dies verhält sich wie erwartet.

Wir könnten auch C# 5.0 ist await Stichwort nutzen Fortsetzungen leichter hinzuzufügen:

public async Task FunctionA() 
{ 
    await Task.Delay(5000); 
    MessageBox.Show("Waiting Complete"); 
} 

Während eine vollständige Erklärung dessen, was hier vor sich geht über den Rahmen dieser Frage ist, ist das Endergebnis ein Verfahren das verhält sich sehr ähnlich zur vorherigen Methode; Es wird 5 Sekunden nach dem Aufruf der Methode ein Meldungsfeld angezeigt, aber die Methode selbst kehrt in beiden Fällen [fast] zurück. Das heißt, await ist sehr leistungsfähig und erlaubt uns, Methoden zu schreiben, die einfach und unkompliziert scheinen, aber das wäre viel schwieriger und unordentlicher zu schreiben mit ContinueWith direkt. Es vereinfacht auch den Umgang mit der Fehlerbehandlung erheblich und entzieht dem Code viel Code.

1

Versuchen Sie es.

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

public async void FunctionA() 
{ 
    await Task.Delay(5000); 
    MessageBox.Show("Waiting Complete"); 
} 
-4

Wie Servy sagte, hat die Aufgabe bereits begonnen, so dass alle Sie zu tun haben, um für sie warten (.Wait()):

private void Button_Click_2(object sender, RoutedEventArgs e) 
{ 
    FunctionA(); 
} 
public void FunctionA() 
{ 
    Task.Delay(5000).Wait(); 
    MessageBox.Show("Waiting Complete"); 
} 
+0

Aufruf 'Wait()' auf eine Aufgabe der blockiert aktueller Thread, bis die Aufgabe aufgelöst wird. Das ist fast nie, was du willst. – Jeremy

+0

@ Jeremy: In der Tat lohnt es sich, auf das von dir erwähnte Verhalten zu achten, aber in diesem Fall blockierte seine FunktionA bereits den aktuellen Thread, also nahm ich an, dass er nur nach einer Möglichkeit sucht, um festzustellen, wann die Aufgabe abgeschlossen ist. Um den Unterschied zwischen Wait und async (für zukünftige Leser) zu verdeutlichen, lesen Sie bitte [link] (http://stackoverflow.com/questions/9519414/whats-the-difference-between-task-start-wait-and-async- erwarten) – Sergiu

Verwandte Themen