Ich muss eine async
Methode in einem catch
Block aufrufen , bevor ich die Ausnahme (mit ihrer Stapelverfolgung) erneut wie folgt auslösen kann:
try
{
// Do something
}
catch
{
// <- Clean things here with async methods
throw;
}
Aber leider kann man nicht await
in einem catch
oder finally
Block verwenden. Ich habe gelernt, dass der Compiler keine Möglichkeit hat, in einen catch
Block zurückzukehren, um das auszuführen, was nach Ihrer await
Anweisung oder so ist ...
Ich habe versucht zu Task.Wait()
ersetzen await
und ich habe einen Deadlock. Ich habe im Web gesucht, wie ich dies vermeiden kann, und diese Website gefunden .
Da ich die async
Methoden nicht ändern kann und auch nicht weiß, ob sie verwendet werden ConfigureAwait(false)
, habe ich diese Methoden erstellt Func<Task>
, die eine asynchrone Methode starten, sobald wir uns in einem anderen Thread befinden (um einen Deadlock zu vermeiden) und auf deren Abschluss warten:
public static void AwaitTaskSync(Func<Task> action)
{
Task.Run(async () => await action().ConfigureAwait(false)).Wait();
}
public static TResult AwaitTaskSync<TResult>(Func<Task<TResult>> action)
{
return Task.Run(async () => await action().ConfigureAwait(false)).Result;
}
public static void AwaitSync(Func<IAsyncAction> action)
{
AwaitTaskSync(() => action().AsTask());
}
public static TResult AwaitSync<TResult>(Func<IAsyncOperation<TResult>> action)
{
return AwaitTaskSync(() => action().AsTask());
}
Meine Fragen sind also: Glaubst du, dieser Code ist in Ordnung?
Natürlich höre ich zu, wenn Sie einige Verbesserungen haben oder einen besseren Ansatz kennen! :) :)
quelle
await
in einem Catch-Block ist seit C # 6.0 tatsächlich zulässig (siehe meine Antwort unten)Antworten:
Sie können die Logik außerhalb des
catch
Blocks verschieben und die Ausnahme nach Bedarf erneut auslösen, indem Sie verwendenExceptionDispatchInfo
.Auf diese Weise zeichnet der Aufrufer beim Überprüfen der Ausnahmeeigenschaft
StackTrace
immer noch auf, woTaskThatFails
sie ausgelöst wurde.quelle
ExceptionDispatchInfo
stattException
(wie in der Antwort von Stephen Cleary)?Exception
, dass Sie alle vorherigen verlieren , wenn Sie sich entscheiden, das erneut zu werfenStackTrace
?Sie sollten wissen, dass es seit C # 6.0 möglich ist,
await
incatch
und zufinally
blockieren, also können Sie dies tatsächlich tun:Die neuen C # 6.0-Funktionen, einschließlich der gerade erwähnten, werden hier oder als Video hier aufgelistet .
quelle
Wenn Sie
async
Fehlerbehandlungsroutinen verwenden müssen, würde ich Folgendes empfehlen:Das Problem beim synchronen Blockieren von
async
Code (unabhängig davon, auf welchem Thread er ausgeführt wird) besteht darin, dass Sie synchron blockieren. In den meisten Szenarien ist es besser zu verwendenawait
.Update: Da Sie neu werfen müssen, können Sie verwenden
ExceptionDispatchInfo
.quelle
throw exception;
in derif
Anweisung verwende, geht die Stapelverfolgung verloren.Wir haben die großartige Antwort von hvd auf die folgende wiederverwendbare Dienstprogrammklasse in unserem Projekt extrahiert :
Man würde es wie folgt verwenden:
Fühlen Sie sich frei, die Benennung zu verbessern, wir haben sie absichtlich ausführlich gehalten. Beachten Sie, dass der Kontext im Wrapper nicht erfasst werden muss, da er bereits auf der Aufrufsite erfasst wurde
ConfigureAwait(false)
.quelle