Wie können Sie CancellationToken abfangen.Rückruf-Ausnahmen registrieren?

8

Ich verwende asynchrone E / A, um mit einem HID-Gerät zu kommunizieren, und ich möchte eine abfangbare Ausnahme auslösen, wenn eine Zeitüberschreitung auftritt. Ich habe die folgende Lesemethode:

%Vor%

Die Ausnahme, die vom Token-Callback ausgelöst wird, wird von keinem try / catch-Block erfasst und ich bin mir nicht sicher warum. Ich nahm an, dass es auf die Wartezeit geworfen werden würde, aber es ist nicht. Gibt es eine Möglichkeit, diese Ausnahme abzufangen (oder durch den Aufrufer von Read ()) abfangbar zu machen?

BEARBEITEN: Also lese ich das Dokument erneut unter msdn und es sagt "Jede Ausnahme, die der Delegat generiert, wird aus diesem Methodenaufruf propagiert."

Ich bin nicht sicher, was es bedeutet, "aus diesem Methodenaufruf propagiert", denn selbst wenn ich den Aufruf .Register () in den try-Block verschiebe, wird die Ausnahme immer noch nicht abgefangen.

    
bj0 12.05.2014, 20:51
quelle

3 Antworten

8
  

BEARBEITEN: Also lese ich das Dokument erneut bei msdn und es steht "Any exception the   Delegate-Generierungen werden aus diesem Methodenaufruf propagiert. "

     

Ich bin nicht sicher, was es bedeutet, "aus diesem Methodenaufruf propagiert",   Denn auch wenn ich den .Register () Aufruf in den try Block verschiebe, wird der   Ausnahme wird immer noch nicht abgefangen.

Das bedeutet, dass der Aufrufer des Rückrufs (der Code innerhalb von .NET Runtime) nicht versuchen wird, irgendwelche Ausnahmen zu fangen, die Sie dorthin werfen können. Daher werden sie außerhalb Ihres Callbacks auf jedem Stack-Frame verbreitet und den Synchronisierungskontext, auf dem der Rückruf aufgerufen wurde. Dies kann die Anwendung zum Absturz bringen, so dass Sie wirklich alle nicht schwerwiegenden Ausnahmen in Ihrem Callback behandeln sollten. Stellen Sie es sich als Event-Handler vor. Immerhin können mehrere Callbacks mit ct.Register() registriert sein, und jeder darf werfen. Welche Ausnahme hätte dann propagiert werden sollen?

Eine solche Ausnahme wird also nicht erfasst und auf die "Client" -Seite des Tokens (d. h. an den Code, der CancellationToken.ThrowIfCancellationRequested aufruft) weitergegeben.

Hier ist ein alternativer Ansatz, um TimeoutException zu werfen, wenn Sie zwischen Benutzerunterdrückung (z. B. einer "Stop" -Schaltfläche) und einem Timeout unterscheiden müssen:

%Vor%     
Noseratio 12.05.2014, 23:29
quelle
7

Ich persönlich bevorzuge es, die Stornierungslogik in eine eigene Methode zu packen.

Zum Beispiel bei einer Erweiterungsmethode wie:

%Vor%

Sie können Ihre Methode auf folgende Weise vereinfachen:

%Vor%

Da in diesem Fall nur ein Timeout durchgeführt werden soll, können Sie dies noch einfacher machen:

%Vor%

Dann kann Ihre Methode lauten:

%Vor%     
Reed Copsey 12.05.2014 21:05
quelle
0

Die Ausnahmebehandlung für Callbacks, die mit CancellationToken.Register() registriert sind, ist komplex. : -)

Token wurde vor der Rückrufregistrierung abgebrochen

Wenn das Stornierungs-Token vor dem Speichern des Stornierungs-Callbacks abgebrochen wird, wird der Callback synchron von CancellationToken.Register() ausgeführt. Wenn der Callback eine Ausnahme auslöst, wird diese Ausnahme von Register() weitergegeben und kann daher mit einem try...catch um sie herum abgefangen werden.

Auf diese Propagierung bezieht sich die von Ihnen zitierte Aussage. Für den Kontext ist hier der vollständige Absatz, aus dem das Zitat stammt.

  

Wenn dieses Token bereits im abgebrochenen Status ist, wird der Delegat sein   sofort und synchron laufen. Jede Ausnahme der Delegat   Generierungen werden aus diesem Methodenaufruf propagiert.

"Dieser Methodenaufruf" bezieht sich auf den Aufruf von CancellationToken.Register() . (Fühlen Sie sich nicht schlecht darüber, von diesem Absatz verwirrt zu sein. Als ich es vor einer Weile zum ersten Mal las, war ich auch verwirrt.)

Token nach Rückrufregistrierung abgebrochen

Wird abgebrochen, indem CancellationTokenSource.Cancel ()

Wenn das Token durch Aufruf dieser Methode abgebrochen wird, werden Stornierungsrückrufe synchron ausgeführt. Abhängig von der Überladung von Cancel() , die verwendet wird, gilt:

  • Alle Stornierungsrückrufe werden ausgeführt. Alle ausgelösten Ausnahmen werden zu einem AggregateException kombiniert, von dem propagiert wird Cancel() .
  • Alle Stornierungsrückrufe werden ausgeführt, solange und bis eine Ausnahme ausgelöst wird. Wenn ein Callback eine Ausnahme auslöst, wird diese Ausnahme von Cancel() (nicht in AggregateException eingeschlossen) weitergegeben und alle nicht ausgeführten Abbruchrückrufe werden übersprungen.

In beiden Fällen, wie CancellationToken.Register() , kann eine normale try...catch verwendet werden, um die Ausnahme abzufangen.

Storniert von CancellationTokenSource.CancelAfter ()

Diese Methode startet einen Countdown-Timer und kehrt dann zurück. Wenn der Timer Null erreicht, bewirkt der Timer, dass der Löschvorgang im Hintergrund ausgeführt wird.

Da CancelAfter() den Löschvorgang nicht tatsächlich ausführt, werden Rückrufausnahmen für die Stornierung nicht weitergegeben. Wenn Sie sie beobachten möchten, müssen Sie einige Methoden zum Abfangen nicht behandelter Ausnahmen verwenden.

In Ihrer Situation, da Sie CancelAfter() verwenden, ist das Abfangen der unbehandelten Ausnahme Ihre einzige Option. try...catch funktioniert nicht.

Empfehlung

Um diese Komplexität zu vermeiden, erlauben Sie, wenn möglich, keine Abbruchrückrufe, um Ausnahmen auszulösen.

Weiter lesen

Ben Gribaudo 09.02.2018 19:31
quelle