Aspetta in blocco di cattura


85

Ho il codice seguente:

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

Fondamentalmente voglio scaricare da un URL e quando fallisce con un'eccezione voglio scaricare da un altro URL. Entrambi i tempi sono asincroni ovviamente. Tuttavia il codice non viene compilato, a causa di

errore CS1985: impossibile attendere nel corpo di una clausola catch

OK, è vietato per qualsiasi motivo, ma qual è il modello di codice corretto qui?

MODIFICARE:

La buona notizia è che C # 6.0 consentirà probabilmente le chiamate in attesa sia nei blocchi catch che in quelli finali .

Risposte:


103

Aggiornamento: C # 6.0 supporta attende in cattura


Vecchia risposta : puoi riscrivere quel codice per spostare il awaitdal catchblocco usando un flag:

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
Grazie svick, è abbastanza ovvio, qualcosa di meglio, più connesso all'asincronia?
György Balássy

Non credo che esista niente del genere.
svick

3
Nel tuo caso, potresti anche utilizzare le continuazioni delle attività. Ma il codice nella svickrisposta di è più pulito del codice che usa le continuazioni.
Stephen Cleary

16
Se hai anche bisogno di rilanciare l'eccezione senza perdere lo stack di chiamate, puoi anche usare la System.Runtime.ExceptionServices.ExceptionDispatchInfoclasse statica. Chiama semplicemente il ExceptionDispatchInfo.Capture(ex)tuo blocco catch e archivia il valore restituito, l'eccezione catturata, in una variabile locale. Una volta che hai finito con il tuo codice asincrono, puoi usare capturedException.Throw()che rilancerà correttamente l'eccezione originale.
Etienne Maheu

tecnica fantastica
Zia Ur Rahman


9

Sembra funzionare.

        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

Provalo:

         try
        {
            await AsyncFunction(...);
        }

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

(Vedi il Wait()finale)


4

Usa C # 6.0. vedere questo collegamento

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

1

Il modello che uso per lanciare nuovamente l'eccezione dopo l'attesa su un'attività di fallback:

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

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

1

Puoi usare un'espressione lambda come segue:

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

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

        lambda(ex);
    }

Questo rende il lambda async void, che non dovrebbe essere usato, a meno che non sia necessario.
svick

0

Potresti mettere il awaitdopo il blocco catch seguito da a labele mettere a gotonel blocco try. (No, davvero! I Goto non sono poi così male!)


0

In un caso simile, non ero in grado di attendere in un blocco di cattura. Tuttavia, sono stato in grado di impostare un flag e utilizzare il flag in un'istruzione if (codice sotto)

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

boolean exceptionFlag = false; 

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

if(exceptionFlag == true){ 
do what you wanted to do in the catch block 
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.