Ожидание в блоке улова

У меня такой код:

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, скорее всего, разрешит вызовы await как в catch, так и в finally блоках < / а>.


person György Balássy    schedule 15.01.2012    source источник


Ответы (9)


Обновление: 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" ) );
person svick    schedule 15.01.2012
comment
Спасибо, svick, это совершенно очевидно, что-нибудь лучше, связанное с async? - person György Balássy; 15.01.2012
comment
Думаю, что ничего подобного не существует. - person svick; 15.01.2012
comment
В вашем случае вы также можете использовать продолжения задач. Но код в ответе svick чище, чем код, использующий продолжения. - person Stephen Cleary; 16.01.2012
comment
Если вам даже нужно повторно вызвать исключение без потери стека вызовов, вы также можете использовать статический класс System.Runtime.ExceptionServices.ExceptionDispatchInfo. Просто вызовите ExceptionDispatchInfo.Capture(ex) в своем блоке catch и сохраните возвращаемое значение, захваченное исключение, в локальной переменной. Как только вы закончите свой асинхронный код, вы можете использовать capturedException.Throw(), который будет правильно повторно генерировать исходное исключение. - person Etienne Maheu; 09.08.2014
comment
потрясающая техника - person Zia Ur Rahman; 13.06.2017
comment
И какая это версия VS? Ответ: C # 6 входит в комплект Visual Studio 2015 (и его превью). - person Tim Lovell-Smith; 22.11.2017

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

Перечисленный пример:

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

Обновление: добавлена ​​более новая ссылка, и она будет на C # 6.

person Craig    schedule 16.04.2014

Кажется, это работает.

        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;
person Darragh    schedule 27.10.2012

Попробуйте:

         try
        {
            await AsyncFunction(...);
        }

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

(См. Финал Wait())

person Ron    schedule 04.03.2015

Используйте C # 6.0. см. это Ссылка

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

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

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

if (capturedException != null)
{
  await FallbackWork();
  capturedException.Throw();
}
person hansmaad    schedule 02.07.2015

Вы можете использовать лямбда-выражение следующим образом:

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

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

        lambda(ex);
    }
person Izmoto    schedule 08.11.2015
comment
Это делает лямбда async void, которую не следует использовать, если вам не нужно. - person svick; 22.11.2017

Вы можете поместить await после блока catch, за которым следует label, и поместить goto в блок try. (Нет, правда! Гото не так уж и плох!)

person Protector one    schedule 10.11.2014

В аналогичном случае я не мог ожидать в блоке 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 
}
person Amanda Berenice    schedule 08.02.2015