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.
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:
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% Die Ausnahmebehandlung für Callbacks, die mit CancellationToken.Register()
registriert sind, ist komplex. : -)
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.)
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:
AggregateException
kombiniert, von dem propagiert wird Cancel()
. 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.
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.
Um diese Komplexität zu vermeiden, erlauben Sie, wenn möglich, keine Abbruchrückrufe, um Ausnahmen auszulösen.
Tags und Links c# task-parallel-library cancellationtokensource