Wo löst eine asynchrone Task eine Exception aus, wenn sie nicht erwartet wird?

7

Ich habe folgendes Beispiel: (Bitte lesen Sie auch Kommentare im Code, da es mehr Sinn ergibt)

%Vor%

Nehmen wir an, die Methode PostAsync von _ mySender sieht folgendermaßen aus:

%Vor%

Die Frage ist:

Da ich nicht auf die tatsächliche Result in der MyAsyncMethod warte und wenn die Methode PostAsync eine Ausnahme auslöst, in welchem ​​Kontext wird die Ausnahme ausgelöst und behandelt?

und

Gibt es eine Möglichkeit, Ausnahmen in meiner Assembly zu behandeln?

Ich war überrascht, als ich MyAsyncMethod zu ändern versuchte:

%Vor%

Die Ausnahme wurde hier abgefangen, Ereignis, wenn das tatsächliche Ergebnis nicht erwartet wird. Es kommt vor, dass das Ergebnis von PostAsync bereits verfügbar ist und die Ausnahme in diesem Kontext geworfen wird, oder?

Kann ContinueWith verwendet werden, um Ausnahmen in der aktuellen Klasse zu behandeln? Zum Beispiel:

%Vor%     
Dan Dinu 05.09.2014, 17:32
quelle

3 Antworten

20

Das sind viele Fragen, die man in eine einzelne "Frage" packen sollte, aber OK ...

  

Wo löst eine asynchrone Task eine Exception aus, wenn sie nicht erwartet wird?

Nicht beobachtete Ausnahmen für Aufgaben werden vom Ereignis TaskScheduler.UnobservedTaskException ausgelöst. Dieses Ereignis wird "möglicherweise" ausgelöst, da der Task tatsächlich "Garbage Collected" sein muss, bevor seine Ausnahme als unbehandelt betrachtet wird.

  

Da ich nicht auf das tatsächliche Ergebnis in MyAsyncMethod warte und die PostAsync-Methode eine Ausnahme auslöst, in welchem ​​Kontext wird die Ausnahme ausgelöst und behandelt?

Jede Methode, die den Modifizierer async verwendet und eine Task zurückgibt, wird alle Ausnahmen auf die zurückgegebene Task anwenden.

  

Gibt es eine Möglichkeit, Ausnahmen in meiner Assembly zu behandeln?

Ja, Sie könnten die zurückgegebene Aufgabe ersetzen, etwa wie folgt:

%Vor%
  

Ich war überrascht, dass, als ich versuchte, MyAsyncMethod zu ändern, um [die innere Aufgabe synchron zurückzugeben], die Ausnahme hier gefangen wurde, selbst wenn das tatsächliche Ergebnis nicht erwartet wird.

Das bedeutet, dass die Methode, die Sie aufrufen, nicht async Task ist, wie Ihr Codebeispiel zeigt. Es ist eine Methode, die nicht async , Task -returning ist, und wenn eine dieser Methoden eine Ausnahme auslöst, wird sie wie jede andere Ausnahme behandelt (dh sie geht direkt über den Call-Stack, sie wird nicht auf den zurückgegebenen% gesetzt co_de%).

  

Ist es möglich, ContinueWith zu verwenden, um Ausnahmen in der aktuellen Klasse zu behandeln?

Ja, aber Task ist sauberer.

    
Stephen Cleary 05.09.2014, 20:00
quelle
6

Ich verwende eine Erweiterungsmethode für die generische Fehlerbehandlung in Task . Dies bietet eine Möglichkeit, alle Fehler zu protokollieren und eine benutzerdefinierte Aktion auszuführen, wenn ein Fehler auftritt.

%Vor%

Ich neige dazu, es zu benutzen, wenn ich "fire and forget" Task :

mache %Vor%     
Zer0 05.09.2014 17:48
quelle
2
  

Da ich nicht auf das tatsächliche Ergebnis in MyAsyncMethod warte und die PostAsync-Methode eine Ausnahme auslöst, in welchem ​​Kontext wird die Ausnahme ausgelöst und behandelt?

Wenn Sie keine der Aufgaben in Ihrem Code await ausführen oder keine Fortsetzung zuweisen, kann sich das Verhalten je nach verwendeter .NET Framework-Version unterscheiden. In beiden Fällen schluckt das zurückgegebene Task die Ausnahme, die Differenz tritt bei der Finalisierung auf:

  1. .NET 4.0 - Der Finalizer-Thread wird die geschluckte Ausnahme erneut auslösen. Wenn kein globaler Ausnahmehandler registriert ist, wird der Prozess beendet

  2. .NET 4.5 und höher - Die Ausnahme wird verschluckt und unbemerkt bleiben.

In beiden Fällen TaskScheduler.UnobservedTaskException Event wird ausgelöst:

  

Tritt auf, wenn die unbeobachtete Ausnahme einer fehlerhaften Aufgabe eine Ausnahmeskalierungsrichtlinie auslöst, die den Prozess standardmäßig beendet.

Wenn eine non async Methode zum Zurückgeben von Tasks synchron ausgeführt wird, wird die Exception sofort propagiert, und deshalb fangen Sie die Exception ab, ohne await zu verwenden, aber Sie sollten definitiv nicht davon abhängig sein das in deinem Code.

  

Gibt es eine Möglichkeit, Ausnahmen in meiner Assembly zu behandeln?

Ja, das kannst du. Ich würde Sie await auf Aufgaben raten, die Sie innerhalb Ihrer Versammlung durchführen.

Es gibt keinen Grund, den Modifizierer async zu verwenden, wenn Sie nichts erwarten:

%Vor%

Dann können Sie await auf PostAsync setzen und die Ausnahme dort abfangen:

%Vor%

Sie können diesen Code sogar noch modifizieren und das async -Schlüsselwort entfernen und möglicherweise die Ausnahme noch höher im Callstack der Methode auffangen, die MyAsyncMethod aufruft.

    
Yuval Itzchakov 05.09.2014 20:28
quelle