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.