C#多个异步方法的异常处理

如果调用两个异步方法,每个都会抛出异常,该如何处理呢 ? 在下面的示例中,第一个 ThrowAfter 方法被调用,2s 后抛出异常(含消息 first)。该方法结束后,另一个 ThrowAfter 方法也被调用,1s 后也抛出异常。事实并非如此,因为对第一个 ThrowAfter 方法的调用已经抛出了异常,try 块内的代码没有继续调用第二个 ThrowAfter 方法,而是在 catch 块内对第一个异常进行处理。.

private static async void StartTwoTasks()
{
  try
  {
    await ThrowAfter(2000, "first");
    await ThrowAfter(1000,  "second"); // the second call is not invoked
    // because the first method throws
    // an exception
  }
  catch (Exception ex)
  {
    Console.WriteLine($"handled  {ex.Message}");
  }
}

现在,并行调用这两个 ThrowAfter 方法。第一个 ThrowAfter 方法 2s 后抛出异常,1s 后第二个 ThrowAfter 方法也抛出异常。使用 Task.WhenAll,不管任务是否抛出异常,都会等到两个任务完成。因此,等待 2s 后, Task.WhenAll 结束,异常被 catch 语句捕获到。但是,只能看见传递给 WhenAll 方法的第一个任务的异常信息,没有显示先抛出异常的任务(第二个任务),但该任务也在列表中:

private async static void StartTwoTasksParallel()
{
  try
  {
    Task tl = ThrowAfter(2000, "first");
    Task t2 = ThrowAfter(1000, "second");
    await Task.WhenAll(tl, t2);
  }
  catch (Exception ex)
  {
    // just display the exception information of the first task
    // that is awaited within whenAll
    Console.WriteLine(S"handled {ex.Message}");
  }
}

有一种方式可以获取所有任务的异常信息,就是在 try 块外声明任务变量 t1 和t2,使它们可以在 catch 块内访问。在这里,可以使用 IsFaulted 属性检查任务的状态,以确认它们是否为出错状态。若出现异常,IsFaulted 属性会返回true。可以使用 Task 类的 Exception.InnerException 访问异常信息本身。