我正在努力更好地掌握 TPL 中异常和错误处理的基本原理(并且在 .NET 4.5 异步/等待任务中运气更好)
对我之前的问题略有修改"How to better understand the code/statements from "Async - Handling multiple Exceptions" article?" C# 控制台应用程序代码运行 2 个分离的内部嵌套 附加(依赖)子项(更新:抱歉,开始了一个问题,但以另一个问题结束!)任务:
class Program
{
static void Main(string[] args)
{ Tst();
Console.ReadLine();
}
async static Task Tst()
{
try
{
await Task.Factory.StartNew
(() =>
{
Task.Factory.StartNew
( () => {
Console.WriteLine("From 1st child");
throw new NullReferenceException();
}
, TaskCreationOptions.AttachedToParent
);
Task.Factory.StartNew
( () =>
{
Console.WriteLine("From 2nd child");
throw new ArgumentException();
}
,TaskCreationOptions.AttachedToParent
);
}
);
}
catch (AggregateException ex)
{
Console.WriteLine("** {0} **", ex.GetType().Name);
foreach (var exc in ex.Flatten().InnerExceptions)
{
Console.WriteLine(exc.GetType().Name);
}
}
catch (Exception ex)
{
Console.WriteLine("## {0} ##", ex.GetType().Name);
}
}
产生在以下之间交替(不确定地)的输出:
From 1st child
From 2nd child
** AggregateException **
ArgumentException
和
From 1t child
From 2nd child
** AggregateException **
NullReferenceException
似乎总是传播/捕获子任务之一中的一个且仅有一个异常。
为什么只传播/捕获一个异常?
如果总是捕获子任务中的任何异常或所有异常,我会更好地理解
在这种情况下,是否有可能同时捕获两个异常或都不捕获异常?
最佳答案
您不应将父/子任务与异步
混合使用。它们并不是设计来一起使用的。
svick 已经在 his (correct) answer to your other question 中回答了这个问题。您可以这样想:
- 每个内部
StartNew
都会获取一个异常,该异常被包装到AggregateException
中并放置在返回的Task
上。 - 外部
StartNew
从其子任务中获取两个AggregateException
,并将其包装到其返回的Task< 上的另一个
。AggregateException
中 - 当您
等待
一个任务
时,会引发第一个内部异常。其他任何内容都将被忽略。
您可以通过保存 Task
并在 await
引发异常后检查它们来观察此行为:
async static Task Test()
{
Task containingTask, nullRefTask, argTask;
try
{
containingTask = Task.Factory.StartNew(() =>
{
nullRefTask = Task.Factory.StartNew(() =>
{
throw new NullReferenceException();
}, TaskCreationOptions.AttachedToParent);
argTask = Task.Factory.StartNew(() =>
{
throw new ArgumentException();
}, TaskCreationOptions.AttachedToParent);
});
await containingTask;
}
catch (AggregateException ex)
{
Console.WriteLine("** {0} **", ex.GetType().Name);
}
}
如果在 WriteLine
上放置断点,您可以看到两个子任务的异常都被放置在父任务上。 await
运算符仅传播其中之一,因此您只能捕获其中一个。
关于c# - 为什么子任务的众多异常中只传播其中之一?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16580125/