Inhaltsverzeichnis
Hier geht es um die Frage, warum sollen wir die Verwendung von async-Methoden mit “void”-Rückgabewert vermeiden und stattdessen die async-Task-Methoden bevorzugen? Und warum erleichtern Async-Task-Methoden die Fehlerbehandlung, Erstellbarkeit und Testbarkeit?
Für async-Methoden gibt es drei mögliche Rückgabetypen:
Task
,Task <T>
undvoid
- aber die standardmäßigen Rückgabetypen für async-Methoden sind nur
Task
undTask<T>
Beim Konvertieren von synchronem Code in asynchronen Code wird:
- jede Methode, die einen Typ
T
zurückgibt, zu einer async-Methode, dieTask <T>
zurückgibt. - jede Methode, die
void
zurückgibt, wird zu einer async-Methode, dieTask
zurückgibt.
Ein Beispiel mit eine synchrone “void” und eine asynchrone Rückgabe :1)Async/Await – Bewährte Verfahren bei der asynchronen Programmierung – MSDN Magazine Issues – Stephen Cleary
// synchronous work void MyMethod() { Thread.Sleep(1000); } // asynchronous work async Task MyMethodAsync() { await Task.Delay(1000); }
Return EventHandler
Async-Methoden, die void
zurückgeben:
- machen asynchrone EventHandler möglich
- können einen
EventHandler
verwenden, der einen tatsächlichen Typ zurückgibt
Die Vorstellung aber, dass ein EventHandler etwas zurückgibt, erscheint nicht sinnvoll. EventHandler geben void
zurück!
Ausnahmebehandlung
Async-void-Methoden haben eine andere Semantiken fürs Exception Handling:
- Bei async-Task- oder
async-Task<T>
-Methode werden Exceptions imTask
-Objekt erfasst. - Bei den async-void-Methoden gibt es kein
Task
-Objekt, sodass alleExceptions
einer async-void-Methode direkt im “SynchronizationContext” ausgelöst werden, der beim Starten der async-void-Methode aktiv war.
Exceptions einer async-void-Methode können nicht im “catch”-Block abgefangen werden.
private async void MyMethodThrowExceptionAsync() { throw new InvalidOperationException(); } public void AsyncVoidExceptions_CannotBeCaughtByCatch() { try { MyMethodThrowExceptionAsync(); } catch (Exception) { // The exception is never caught here! throw; } }
Diese Exceptions können zwar mit einem Catch-All-Ereignis abgefangen werden, die Verwendung dieser Ereignisse für die allgemeine Ausnahmebehandlung erfordert jedoch einen sehr hohen Wartungsaufwand.
Start- und Endzeitpunkt
Async-void-Methoden weisen auch andere Erstellungssemantiken auf:
- Async-Methoden, die
Task
oderTask<T>
zurückgeben, können ganz einfach mitawait
,Task.WhenAny
,Task.WhenAll
usw. erstellt werden. - Async-Methoden, die
void
zurückgeben, bieten keine einfache Möglichkeit, dem aufrufenden Code mitzuteilen, dass sie abgeschlossen sind.
Es ist leicht, mehrere async-void-Methoden zu starten, es ist aber nicht leicht festzustellen, wann sie beendet wurden.
Tests
Async-void-Methoden sind schwierig zu testen. Aufgrund der Unterschiede in der Fehlerbehandlung und in der Erstellung ist es schwierig, Komponententests zu schreiben, die async-void-Methoden aufrufen.
Testbar
Besser wäre: Den Code in einem asynchronen EventHandler zu minimieren und ihn auf eine async-Task-Methode warten zu lasse, die die eigentliche Logik enthält.
private async void Button_Click(object sender, EventArgs e) { await ButtonClickAsync(); } public async Task ButtonClickAsync() { // Do asynchronous work. await Task.Delay(1000); }