【发布时间】:2025-12-13 20:30:02
【问题描述】:
运行以下 C# 控制台应用程序
class Program
{ static void Main(string[] args)
{ Tst();
Console.ReadLine();
}
async static Task Tst()
{
try
{
await Task.Factory.StartNew
(() =>
{
Task.Factory.StartNew
(() =>
{ throw new NullReferenceException(); }
, TaskCreationOptions.AttachedToParent
);
Task.Factory.StartNew
( () =>
{ throw new ArgumentException(); }
,TaskCreationOptions.AttachedToParent
);
}
);
}
catch (AggregateException ex)
{
// this catch will never be target
Console.WriteLine("** {0} **", ex.GetType().Name);
//****** Update1 - Start of Added code
foreach (var exc in ex.Flatten().InnerExceptions)
{
Console.WriteLine(exc.GetType().Name);
}
//****** Update1 - End of Added code
}
catch (Exception ex)
{
Console.WriteLine("## {0} ##", ex.GetType().Name);
}
}
产生输出:
** AggregateException **
不过,上面的代码是从"Async - Handling multiple Exceptions" 博客文章中复制第一个sn-p,它讲述了它:
以下代码将捕获单个 NullReferenceException 或 ArgumentException 异常(AggregateException 将被忽略)
问题出在哪里:
- 文章有误?
哪些代码/语句以及如何更改以正确理解它? - 我在复制文章的第一个代码sn-p时出错了?
- 这是由于 .NET 4.0/VS2010 Async CTP 扩展中的一个错误,我正在使用?
Update1(响应svick's answer)
添加代码后
//****** Update1 - Start of Added code
foreach (var exc in ex.Flatten().InnerExceptions)
{
Console.WriteLine(exc.GetType().Name);
}
//****** Update1 - End of Added code
产生的输出是:
** AggregateException **
NullReferenceException
被捕获的
AggregateException仅包含其中一个 抛出的异常(NullReferenceException或ArgumentException取决于孩子的执行顺序 任务)
很可能,这篇文章仍然正确,或者至少,非常有用。我只需要了解如何更好地阅读/理解/使用它
Update2(响应svick's answer)
执行svick的代码:
internal class Program
{
private static void Main(string[] args)
{
Tst();
Console.ReadLine();
}
private static async Task Tst()
{
try
{
await TaskEx.WhenAll
(
Task.Factory.StartNew
(() =>
{ throw new NullReferenceException(); }
//, TaskCreationOptions.AttachedToParent
),
Task.Factory.StartNew
(() =>
{ throw new ArgumentException(); }
//,TaskCreationOptions.AttachedToParent
)
);
}
catch (AggregateException ex)
{
// this catch will never be target
Console.WriteLine("** {0} **", ex.GetType().Name);
//****** Update1 - Start of Added code
foreach (var exc in ex.Flatten().InnerExceptions)
{
Console.WriteLine("==="+exc.GetType().Name);
}
//****** Update1 - End of Added code
}
catch (Exception ex)
{
Console.WriteLine("## {0} ##", ex.GetType().Name);
}
}
}
产生:
## NullReferenceException ##
输出。
为什么AggregateException 没有被生产或捕获?
【问题讨论】:
-
我在 VS2012 和 .Net4.5 上看到了相同的结果。我很确定这篇文章是错误的。使用
AttachedToParent意味着异常将被自动传播(即使没有await、Wait()、.Result调用),但父Task仍将抛出一个AggregateException,其内部异常对应于实际抛出的异常。 -
@dlev,谢谢。您可以将您的评论复制粘贴到答案部分吗?我正在考虑发布有关子任务和分离嵌套任务之间异常传播差异的问题
-
注意,dlev 的评论有点误导:如果您使用
Wait或Result,您将得到包含所有异常的外部AggregateException。如果您执行await,您将获得内部AggregateExceptions 之一,它表示只有一个 子Tasks 引发的异常。 -
@MattSmith,如果你把你的 cmets 作为答案,我会很感激
-
#dlev,刚刚从我的休眠状态(睡眠)退出后检查 - 没有
await没有捕获到异常(但await只捕获了 2 个中的 1 个)
标签: c# exception-handling task-parallel-library async-await async-ctp