Warten Sie im Fangblock


85

Ich habe folgenden Code:

WebClient wc = new WebClient();
string result;
try
{
  result = await wc.DownloadStringTaskAsync( new Uri( "http://badurl" ) );
}
catch
{
  result = await wc.DownloadStringTaskAsync( new Uri( "http://fallbackurl" ) );
}

Grundsätzlich möchte ich von einer URL herunterladen und wenn es mit einer Ausnahme fehlschlägt, möchte ich von einer anderen URL herunterladen. Beide Male natürlich asynchron. Der Code wird jedoch aufgrund von nicht kompiliert

Fehler CS1985: Kann im Hauptteil einer catch-Klausel nicht warten

OK, es ist aus irgendeinem Grund verboten, aber wie lautet das richtige Codemuster hier?

BEARBEITEN:

Die gute Nachricht ist, dass C # 6.0 wahrscheinlich das Warten auf Anrufe sowohl im Catch- als auch im Endblock ermöglicht .

Antworten:


103

Update: C # 6.0 unterstützt das Warten im Fang


Alte Antwort : Sie können diesen Code neu schreiben, um ihn mit einem Flag awaitaus dem catchBlock zu verschieben :

WebClient wc = new WebClient();
string result = null;
bool downloadSucceeded;
try
{
  result = await wc.DownloadStringTaskAsync( new Uri( "http://badurl" ) );
  downloadSucceeded = true;
}
catch
{
  downloadSucceeded = false;
}

if (!downloadSucceeded)
  result = await wc.DownloadStringTaskAsync( new Uri( "http://fallbackurl" ) );

7
Danke svick, das ist ganz offensichtlich, etwas Besseres, mehr mit Async verbunden?
György Balássy

Ich glaube nicht, dass so etwas existiert.
Svick

3
In Ihrem Fall können Sie auch Aufgabenfortsetzungen verwenden. Der Code in svickder Antwort ist jedoch sauberer als der Code mit Fortsetzungen.
Stephen Cleary

16
Wenn Sie die Ausnahme erneut auslösen müssen, ohne den Callstack zu verlieren, können Sie auch die System.Runtime.ExceptionServices.ExceptionDispatchInfostatische Klasse verwenden. Rufen ExceptionDispatchInfo.Capture(ex)Sie einfach Ihren catch-Block auf und speichern Sie den Rückgabewert, die erfasste Ausnahme, in einer lokalen Variablen. Sobald Sie mit Ihrem asynchronen Code fertig sind, können Sie verwenden, capturedException.Throw()wodurch die ursprüngliche Ausnahme ordnungsgemäß erneut ausgelöst wird.
Etienne Maheu

tolle Technik
Zia Ur Rahman


9

Das scheint zu funktionieren.

        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;

6

Probieren Sie es aus:

         try
        {
            await AsyncFunction(...);
        }

        catch(Exception ex)
        { 
            Utilities.LogExceptionToFile(ex).Wait();
            //instead of "await Utilities.LogExceptionToFile(ex);"
        }

(Siehe das Wait()Ende)


4

Verwenden Sie C # 6.0. siehe diesen Link

public async Task SubmitDataToServer()
{
  try
  {
    // Submit Data
  }
  catch
  {
    await LogExceptionAsync();
  }
  finally
  {
    await CloseConnectionAsync();
  }
}

1

Das Muster, mit dem ich die Ausnahme nach dem Warten auf eine Fallback-Aufgabe erneut auslöse:

ExceptionDispatchInfo capturedException = null;
try
{
  await SomeWork();
}
catch (Exception e)
{
  capturedException = ExceptionDispatchInfo.Capture(e);
}

if (capturedException != null)
{
  await FallbackWork();
  capturedException.Throw();
}

1

Sie können einen Lambda-Ausdruck wie folgt verwenden:

  try
    {
        //.....
    }
    catch (Exception ex)
    {
        Action<Exception> lambda;

        lambda = async (x) =>
        {
            // await (...);
        };

        lambda(ex);
    }

Dies macht das Lambda async void, das nicht verwendet werden sollte, es sei denn, Sie müssen.
Svick

0

Sie können das awaitnach dem catch-Block gefolgt von a labelsetzen und ein gotoin den try-Block setzen. (Nein, wirklich! Goto ist nicht so schlimm!)


0

In einem ähnlichen Fall konnte ich nicht in einem Fangblock warten. Ich konnte jedoch ein Flag setzen und das Flag in einer if-Anweisung verwenden (Code unten).

---------------------------------------...

boolean exceptionFlag = false; 

try 
{ 
do your thing 
} 
catch 
{ 
exceptionFlag = true; 
} 

if(exceptionFlag == true){ 
do what you wanted to do in the catch block 
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.