任务异常管理 c#
本文关键字:管理 异常 任务 | 更新日期: 2023-09-27 18:37:22
我运行一个包含 2 个项目的解决方案:应用程序和 SDK。
通过该应用程序,我创建了 sdk 的实例,以便应用程序可以启动。问题是,当我在任务中运行的代码部分出现异常时,不会引发未处理的异常,因此我的应用程序继续运行并且没有意识到 SDK 中发生了意外情况。
我在应用程序和 SDK 中注册了 AppDomain.CurrentDomain.UnhandledException
的事件,但如前所述,当在任务中引发异常时,不会调用事件处理程序。
我缺少什么吗?
这两个答案都有些(但不完全)完整。
异步
处理错误任务的最佳方法是使用 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"/>
。您可以改用事件本身来处理异常,这不是最佳的,原因有两个:
- .Net 仅当任务被垃圾回收时才确定任务的异常未被观察到,这随时可能发生(或者永远不会,如果你不释放对它的所有引用)。在此之前,您仍然可以自己处理异常,因此尚未观察到异常。
- 您得到的是异常,但不是任务,如果没有它,可能很难知道问题的真正起源。
结论
确保await
任务以在异常发生时处理异常。还可以使用UnobservedTaskException
作为全部捕获,以防您错过任务。
当Task
引发未经处理的异常时,其执行将终止,您可以检查原始Task
对象的IsFaulted
和Exception
属性。
有关这些属性的详细信息,请参阅此处和此处,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 行为
几种方法可以解决此问题:
- 在代码中使用
await Task.Run
。await
将从任务内部解包异常。 如果您不想等待并想使用"即发即弃"方法,则可以附加一个延续:
Task.Run(() => {}).ContinueWith(task => { */ Handle Exceptions here */ }, TaskContinutationOptions.OnlyOnFaulted);