异步方法中的异常处理C#

时间:2014-11-12 18:44:39

标签: c# .net exception-handling

我知道这个问题已被问过好几次了,但是,我正在略微考虑一个不同的变体。

public async Task<string> SomeAsyncMethod(string url)
{
     // do some URL validation
     if (!valid)
     {
          throw new Exception("some error");
     }
     // do async stuff now
     return await GetFromUrl(url)
}

// now in caller
public async Task<string> SomeOtherAsyncMethod(string input)
{
     var task = SomeAsyncMethod(input); 
    // there is potential chance that a validation fails and  
    //exception is thrown even before entering async parts of the called function

     // do some independent stuff here
    try
    {
        await task;
    } 
    catch(Exception e)
    {
        // log error 
    }

    // is the following code correct way to handle exceptions?
    if (!task.IsFaulted)
    {
        return task.Result; 
    }

    // log error from task.Exception 
    return null;

}

在上面的代码中,可能会发生验证失败,甚至在控件进入方法的异步部分之前抛出异常。我们是否需要围绕try..catch块包装第一个调用?我的实验表明这没用。而是将任务状态设置为Faulted。因此,我认为检查任务状态并相应地返回数据是正确的。 C#专业人士可以对此发表评论吗?

2 个答案:

答案 0 :(得分:3)

正如您已经说过的,当您使用async方法抛出异常时,调用该方法将永远不会抛出,而返回的任务将会出现故障。即使在第一个await之前抛出异常,也是如此。如果这是您想要的功能,那么您已经拥有它,并且无需进行任何更改。

答案 1 :(得分:3)

  

我们是否需要围绕try..catch块包装第一个调用?

您可能希望这样做,作为防御性编码措施。 async方法中的“前置条件”异常遇到与枚举器块相同的问题。在async情况下,前提条件异常用于故障任务,而不是直接引发。这就是我如何预处理异常。

然而,还有另一种选择。实现可能“急切地”执行前提条件检查,并仅使用故障任务来表示异步异常。即:

public Task<string> SomeMethodAsync(string url)
{
   // do some URL validation
   if (!valid)
   {
     throw new Exception("some error");
   }
   // do async stuff now
   return SomeMethodImplAsync(url);
}

private async Task<string> SomeMethodImplAsync(string url)
{
  return await GetFromUrl(url)
}

我自己不这样做,但这种做法确实有它的支持者。最值得注意的是,Jon Skeet。

考虑到这一点,除非文档明确指出将在返回的任务上放置前置条件异常,否则您可能应该在SomeMethdAsync块中包含对try的调用。