Чекаємо в блоці лову


85

У мене є такий код:

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

В основному я хочу завантажити з URL-адреси, а коли це не вдається, за винятком, я хочу завантажити з іншої URL-адреси. Звичайно, і час асинхронний. Однак код не компілюється через

помилка CS1985: Не можу дочекатися в тілі пропозиції catch

Добре, це заборонено з будь-якої причини, але який тут правильний шаблон коду?

РЕДАГУВАТИ:

Хороша новина полягає в тому, що C # 6.0, ймовірно, дозволить очікувати дзвінки як в catch, так і нарешті в блоках .

Відповіді:


103

Оновлення: C # 6.0 підтримує очікування в catch


Стара відповідь : Ви можете переписати цей код для переміщення awaitз catchблоку, використовуючи прапор:

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
Завдяки svick, це цілком очевидно, щось краще, більш підключене до асинхронізації?
György Balássy

Я не думаю, що щось подібне існує.
svick

3
У вашому випадку ви також можете використовувати продовження завдання. Але код у svickвідповіді чистіший, ніж код, що використовує продовження.
Стівен Клірі,

16
Якщо вам навіть потрібно відновити виняток, не втрачаючи стек викликів, ви також можете використовувати System.Runtime.ExceptionServices.ExceptionDispatchInfoстатичний клас. Просто зателефонуйте ExceptionDispatchInfo.Capture(ex)у свій блок catch і збережіть значення повернення, захоплений виняток, у локальній змінній. Після того, як ви закінчите з асинхронним кодом, ви можете скористатися ним, capturedException.Throw()який правильно відновить початковий виняток.
Etienne Maheu

дивовижна техніка
Зія Ур Рахман

24

Очікування в блоці catch тепер можливе з попереднього перегляду Roslyn для кінцевого користувача, як показано тут (перераховано в розділі Очікуйте в catch / нарешті) і буде включено в C # 6.

Наведений приклад є

try … catch { await … } finally { await … }

Оновлення: Додано нове посилання, і воно буде в C # 6


9

Здається, це працює.

        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

Спробуйте:

         try
        {
            await AsyncFunction(...);
        }

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

(Див. Wait()Закінчення)


4

Використовуйте C # 6.0. дивіться це посилання

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

1

Шаблон, який я використовую для відновлення винятку після очікування на резервне завдання:

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

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

1

Ви можете використовувати лямбда-вираз наступним чином:

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

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

        lambda(ex);
    }

Це робить лямбду async void, яку не слід використовувати, якщо тільки вам не потрібно.
свик

0

Ви можете поставити awaitблок after catch, за яким слідує a label, і поставити a gotoв блок try. (Ні, справді! Гото не так вже й погано!)


0

У подібному випадку я не міг чекати в блоці catch. Однак мені вдалося встановити прапор і використовувати прапор у операторі if (код нижче)

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

boolean exceptionFlag = false; 

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

if(exceptionFlag == true){ 
do what you wanted to do in the catch block 
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.