在捕获块中等待


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和finally块中的等待调用

Answers:


103

更新: C#6.0支持等待捕获


旧答案:您可以重写该代码以使用标志将其awaitcatch块中移出:

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,这是显而易见的,还有什么更好的,与异步更多的连接?
捷尔吉Balássy

我认为不存在那样的东西。
svick 2012年

3
在您的情况下,您也可以使用任务继续。但是svick答案中的代码比使用延续的代码更干净。
Stephen Cleary 2012年

16
如果您甚至需要在不丢失调用堆栈的情况下重新抛出异常,则也可以使用 System.Runtime.ExceptionServices.ExceptionDispatchInfo静态类。只需调用ExceptionDispatchInfo.Capture(ex)您的catch块并将返回值,捕获的异常存储在本地变量中即可。异步代码完成后,您可以使用capturedException.Throw()后者正确地抛出原始异常。
Etienne Maheu 2014年

很棒的技术
Zia Ur Rahman


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

您可以使用lambda表达式,如下所示:

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

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

        lambda(ex);
    }

这将导致lambda async void,除非必须使用,否则不应使用。
svick

0

您可以将awaitcatch放在catch块之后label,然后将放在gototry块中。(不,真的!Goto的还不错!)


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 
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.