任务异常管理 c#

本文关键字:管理 异常 任务 | 更新日期: 2023-09-27 18:37:22

我运行一个包含 2 个项目的解决方案:应用程序和 SDK。

通过该应用程序,我创建了 sdk 的实例,以便应用程序可以启动。问题是,当我在任务中运行的代码部分出现异常时,不会引发未处理的异常,因此我的应用程序继续运行并且没有意识到 SDK 中发生了意外情况。

我在应用程序和 SDK 中注册了 AppDomain.CurrentDomain.UnhandledException 的事件,但如前所述,当在任务中引发异常时,不会调用事件处理程序。

我缺少什么吗?

任务异常管理 c#

这两个答案都有些(但不完全)完整。

异步

处理错误任务的最佳方法是使用 await 异步等待它完成。这将重新引发原始存储的异常:

try
{
    await task;
}
catch (Exception e)
{
    // handle exception
}

同步

如果你不能这样做(或不想这样做),你也可以使用task.Wait()同步等待,并在InnerExceptions中抛出一个包含原始异常的AggregateException,或者注册一个处理它的延续(即 task.ContinueWith(t => // handle exception)

UnobservedTaskException

在 .Net 4.0 中,未观察到的任务异常会导致整个过程停机。TaskScheduler.UnobservedTaskException事件是崩溃前处理异常的最后一个选项(与UnhandledException的情况非常相似)。在 .Net 4.5 中,此类异常不再导致应用崩溃,但仍会引发事件

如果您想在这种情况下使应用程序崩溃(我怀疑您这样做),您可以按照 Yuval 指出的设置<ThrowUnobservedTaskExceptions enabled="true"/>。您可以改用事件本身来处理异常,这不是最佳的,原因有两个:

  1. .Net 仅当任务被垃圾回收时才确定任务的异常未被观察到,这随时可能发生(或者永远不会,如果你不释放对它的所有引用)。在此之前,您仍然可以自己处理异常,因此尚未观察到异常。
  2. 您得到的是异常,但不是任务,如果没有它,可能很难知道问题的真正起源。

结论

确保await任务以在异常发生时处理异常。还可以使用UnobservedTaskException作为全部捕获,以防您错过任务。

Task引发未经处理的异常时,其执行将终止,您可以检查原始Task对象的IsFaultedException属性。

有关这些属性的详细信息,请参阅此处和此处,MSDN 上的任务中有一篇专门介绍异常处理的文章

您还有TaskScheduler上的UnobservedTaskException事件。我自己从未使用过它,但阅读它,它应该类似于AppDomain上的UnhandledException事件。在 MSDN 上检查它

问题是当我在运行的代码部分出现异常时 在任务中,不会引发未处理的异常,因此我的应用程序保持 正在运行,但没有意识到 SDK 中发生了意外情况。

这并不完全正确(感谢@l3arnon的更正):Task将在 .NET 4.0 和 .NET 4.5 中传播异常,并将触发UnobservedTaskException。两者之间的区别在于,.NET 4.5 将在触发后悄悄吞下异常,而 .NET 4.0 则在事件未处理时会使进程崩溃。

您可以通过"app.config and ThrowUnobservedTaskExceptions"更改回 .NET 4.0 行为

还有其他

几种方法可以解决此问题:

  1. 在代码中使用await Task.Runawait将从任务内部解包异常。
  2. 如果您不想等待并想使用"即发即弃"方法,则可以附加一个延续:

    Task.Run(() => {}).ContinueWith(task => { */ Handle Exceptions here */ },
                                    TaskContinutationOptions.OnlyOnFaulted);