Mam następujący kod:
WebClient wc = new WebClient();
string result;
try
{
result = await wc.DownloadStringTaskAsync( new Uri( "http://badurl" ) );
}
catch
{
result = await wc.DownloadStringTaskAsync( new Uri( "http://fallbackurl" ) );
}
Zasadniczo chcę pobierać z adresu URL, a jeśli się nie powiedzie, z wyjątkiem, chcę pobrać z innego adresu URL. Oczywiście oba czasy są asynchroniczne. Jednak kod nie kompiluje się z powodu
błąd CS1985: nie można czekać w treści klauzuli catch
OK, z jakiegoś powodu jest to zabronione, ale jaki jest prawidłowy wzorzec kodu?
EDYTOWAĆ:
Dobrą wiadomością jest to, że C # 6.0 prawdopodobnie zezwoli na wywołania await zarówno w blokach catch, jak i na końcu .
c#
asynchronous
async-await
c#-5.0
c#-6.0
György Balássy
źródło
źródło
svick
odpowiedzi jest czystszy niż kod używający kontynuacji.System.Runtime.ExceptionServices.ExceptionDispatchInfo
klasy statycznej. Po prostu wywołajExceptionDispatchInfo.Capture(ex)
swój blok catch i zapisz zwracaną wartość, przechwycony wyjątek, w zmiennej lokalnej. Gdy skończysz z kodem asynchronicznym, możesz użyć,capturedException.Throw()
który poprawnie wyrzuci oryginalny wyjątek.Oczekiwanie na blok catch jest teraz możliwe w podglądzie użytkownika końcowego Roslyn, jak pokazano tutaj (wymienione w sekcji Oczekiwanie w catch / Ostatnim) i zostanie uwzględnione w C # 6.
Podany przykład to
try … catch { await … } finally { await … }
Aktualizacja: Dodano nowszy link i że będzie w C # 6
źródło
To wydaje się działać.
WebClient wc = new WebClient(); string result; Task<string> downloadTask = wc.DownloadStringTaskAsync(new Uri("http://badurl")); downloadTask = downloadTask.ContinueWith( t => { return wc.DownloadStringTaskAsync(new Uri("http://google.com/")).Result; }, TaskContinuationOptions.OnlyOnFaulted); result = await downloadTask;
źródło
Spróbuj:
try { await AsyncFunction(...); } catch(Exception ex) { Utilities.LogExceptionToFile(ex).Wait(); //instead of "await Utilities.LogExceptionToFile(ex);" }
(Zobacz
Wait()
zakończenie)źródło
Użyj C # 6.0. zobacz ten link
public async Task SubmitDataToServer() { try { // Submit Data } catch { await LogExceptionAsync(); } finally { await CloseConnectionAsync(); } }
źródło
Wzorzec, którego używam, aby ponownie zgłosić wyjątek po oczekiwaniu na zadanie rezerwowe:
ExceptionDispatchInfo capturedException = null; try { await SomeWork(); } catch (Exception e) { capturedException = ExceptionDispatchInfo.Capture(e); } if (capturedException != null) { await FallbackWork(); capturedException.Throw(); }
źródło
Możesz użyć wyrażenia lambda w następujący sposób:
try { //..... } catch (Exception ex) { Action<Exception> lambda; lambda = async (x) => { // await (...); }; lambda(ex); }
źródło
async void
, które nie powinny być używane, chyba że musisz.Możesz umieścić
await
po bloku catch, po którym następuje alabel
, i wstawić agoto
w bloku try. (Nie, naprawdę! Gotowe nie są takie złe!)źródło
W podobnym przypadku nie mogłem czekać w bloku catch. Jednak udało mi się ustawić flagę i użyć flagi w instrukcji if (kod poniżej)
---------------------------------------...
boolean exceptionFlag = false; try { do your thing } catch { exceptionFlag = true; } if(exceptionFlag == true){ do what you wanted to do in the catch block }
źródło