【问题标题】:TimeoutException, TaskCanceledException C#超时异常,任务取消异常 C#
【发布时间】:2014-07-21 13:35:37
【问题描述】:

我是 C# 新手,我发现异常有点令人困惑... 我有一个带有以下代码的网络应用程序:

try
{
    //do something
}
catch (TimeoutException t)
{
    Console.WriteLine(t);
}
catch (TaskCanceledException tc)
{
    Console.WriteLine(tc);
}
catch (Exception e)
{
    Console.WriteLine(e);
}

当我调试代码时,它会抛出 e Exception,这是最常见的一个,当我将鼠标悬停在异常信息上时,结果发现它是 TaskCanceledException。为什么TaskCanceledException 没有被抓到?如果异常是TimeoutException,它会捕获TimeoutException,还是也会捕获Exception?这是为什么呢?

【问题讨论】:

  • 你确定这不是从Task 对象抛出的AggregationException 吗?向我们展示投掷电话
  • ...是的,它是 System.AggregateException 而 InnerException 是 System.Threading.Task.TaskCanceledException。

标签: c# exception-handling timeoutexception


【解决方案1】:

当捕获 Exception 时,您必须确保它正是被抛出的异常。当使用Task.RunTask.Factory.Startnew 并且通常涉及从Task 引发的异常时(除非使用await 关键字等待任务),您正在处理的外部异常是AggregateException,因为Task 单元可能有子任务,这些任务也可能引发异常。

来自Exception Handling (Task Parallel Library)

正在运行的用户代码引发的未处理异常 任务内部被传播回加入线程,除了在 本主题后面描述的某些场景。例外 当您使用静态或实例 Task.Wait 或 Task.Wait 方法,您可以通过封装调用来处理它们 在 try-catch 语句中。如果任务是附加孩子的父母 任务,或者如果您正在等待多个任务,那么多个 可能会抛出异常。将所有异常传播回 调用线程,任务基础设施将它们包装在一个 聚合异常实例。 AggregateException 有一个 可以枚举的 InnerExceptions 属性来检查所有 抛出的原始异常,并处理(或不处理)每个 一个人。即使只抛出一个异常,它仍然是 包装在 AggregateException 中。

所以,为了解决这个问题,你必须抓住AggregateException

try
{
    //do something
}
catch (TimeoutException t)
{
    Console.WriteLine(t);
}
catch (TaskCanceledException tc)
{
    Console.WriteLine(tc);
}
catch (AggregateException ae)
{
   // This may contain multiple exceptions, which you can iterate with a foreach
   foreach (var exception in ae.InnerExceptions)
   {
       Console.WriteLine(exception.Message);
   }
}
catch (Exception e)
{
    Console.WriteLine(e);
}

【讨论】:

  • 好的。现在我的应用程序应该超时,但我得到的不是 TimeoutException,而是内部带有 TaskCanceledException 的 AggregateException。如何让程序捕获 TimeoutException?
  • 基本上可以抛出 TimeoutException 而不是 TaskCanceledException 吗?
  • 不,这是不可能的。 AggregateExcception 是从 Task 抛出的,因为它也可能包含子任务。它只是一个包装器。