C# 如何正确地重新引发已处于故障状态的任务的异常?
我有一个同步方法,其中包括检查挂起任务的状态,并重试其异常(如果有):C# 如何正确地重新引发已处于故障状态的任务的异常?,c#,.net,task-parallel-library,async-await,C#,.net,Task Parallel Library,Async Await,我有一个同步方法,其中包括检查挂起任务的状态,并重试其异常(如果有): void Test(Task task) { // ... if (task.IsFaulted) throw task.Exception; // ... } 这不会传播异常堆栈跟踪信息,并且对调试器不友好 现在,如果测试是异步的,它就不会像这样简单和自然了: async Task Test(Task task) { // ... if (task.IsFaulte
void Test(Task task)
{
// ...
if (task.IsFaulted)
throw task.Exception;
// ...
}
这不会传播异常堆栈跟踪信息,并且对调试器不友好
现在,如果测试
是异步的
,它就不会像这样简单和自然了:
async Task Test(Task task)
{
// ...
if (task.IsFaulted)
await task; // rethrow immediately and correctly
// ...
}
问题:如何为同步方法做好准备?我已经想到了这一点,但我不喜欢它:
void Test(Task task)
{
// ...
if (task.IsFaulted)
new Action(async () => await task)();
// ...
}
要正确地重新引发异常,应使用
ExceptionDispatchInfo
:
ExceptionDispatchInfo.Capture(task.Exception.InnerException).Throw();
您还可以执行以下操作:
另外,您的
操作
方法将无法正常工作,因为您正在创建一个异步void
方法,并且无法捕获从该方法传播的异常。可能尝试访问任务。结果?@Strilanc,这是一个非通用的任务
任务,因此它没有结果
。感谢@StephenCleary提供全面的答案,我学到了有关异步void
的新知识。我认为,由于task
已经处于完成状态,因此新操作(async()=>await task)(
lambda将同步执行,从而引发调用线程的同步上下文。事实上,它是同步执行的,但异常不会传播到调用上下文中。我刚刚意识到,我还可以使用task.Wait()
在非异步方法中重新执行,即if(task.IsFaulted)task.Wait()代码>。不过,我确实得到了AggregatedException
。这有意义吗?@avo:是的,有意义Wait
是任务
类型从其原始设计中保留下来的,它是并行任务库的一部分。因此,Wait
(和Result
)将1)在必要时阻塞线程,2)在aggregateeexception
中包装任何错误。这是意料之中的,这就是为什么我的示例代码实际抛出InnerException
。
task.GetAwaiter().GetResult();