超时异常,任务取消异常 C#

7

我是C#的新手,对于异常有点困惑... 我有一个包含以下代码的Web应用程序:

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

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


3
你确定这不是从一个Task对象抛出的AggregationException吗?请展示抛出的调用。 - Yuval Itzchakov
是的,它是System.AggregateException,而InnerException是System.Threading.Task.TaskCanceledException。 - Marta
1个回答

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

来自Exception Handling (Task Parallel Library)

在任务中抛出的未处理异常会传播回加入线程,除非在本主题后面描述的某些情况下。当使用静态或实例Task.Wait或Task.Wait方法并通过将调用包含在try-catch语句中来处理它们时,异常会被传播。如果任务是附加子任务的父任务,或者您正在等待多个任务,则可能会抛出多个异常。为了将所有异常传播回调用线程,任务基础结构将它们包装在AggregateException实例中。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);
}

好的。现在我的应用程序应该超时,但是我得到的是一个包含TaskCanceledException的AggregateException。我该如何让程序捕获TimeoutException? - Marta
基本上,超时异常(TimeoutException)可以被抛出,而不是任务取消异常(TaskCanceledException)吗? - Marta
不,这是不可能的。AggregateException从一个Task中抛出,因为它可能还包含子任务。它只是一个包装器。 - Yuval Itzchakov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接