如何更好地理解“异步-处理多个异常”中的代码/语句;篇文章
本文关键字:异常 代码 文章 语句 处理 更好 何更好 异步 | 更新日期: 2023-09-27 18:13:58
运行以下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 -处理多个异常"博客文章中复制的第一个片段,它告诉我们:
下面的代码将捕获单个NullReferenceException或ArgumentException异常(AggregateException将被忽略)
问题在哪里:
- 这篇文章是错的?
- 我在复制文章的第一个代码片段时犯了错误?
- 这是由于一个错误在。net 4.0/VS2010异步CTP扩展,我使用?
哪些代码/语句以及如何更改才能正确理解它?
Update1(在响应svick的回答)
添加代码
后//****** Update1 - Start of Added code
foreach (var exc in ex.Flatten().InnerExceptions)
{
Console.WriteLine(exc.GetType().Name);
}
//****** Update1 - End of Added code
产生的输出是:
** AggregateException **
NullReferenceException
所以,正如Matt Smith所说:
最有可能的是,文章仍然被捕获的
AggregateException
只包含一个抛出的异常(NullReferenceException
或ArgumentException
取决于子进程的执行顺序任务)
Update2(在响应svick的回答)
执行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
?
文章有误。在运行代码时,await
和Task
包含一个异常,看起来像这样:
AggregateException
AggregateException
NullReferenceException
AggregateException
ArgumentException
await
(或者更具体地说,TaskAwaiter.GetResult()
)在这里所做的是获取外部的AggregateException
并重新抛出它的第一个子异常。这里,这是另一个AggregateException
,这就是抛出的内容。
Task
有多个异常,其中一个在await
之后被直接重新抛出的代码示例是使用Task.WhenAll()
而不是AttachedToParent
:
try
{
await Task.WhenAll(
Task.Factory.StartNew(() => { throw new NullReferenceException(); }),
Task.Factory.StartNew(() => { throw new ArgumentException(); }));
}
catch (AggregateException ex)
{
// this catch will never be target
Console.WriteLine("** {0} **", ex.GetType().Name);
}
catch (Exception ex)
{
Console.WriteLine("## {0} ##", ex.GetType().Name);
}
回应你的"Update 2",推理仍然和svick的答案一样。该任务包含一个AggregateException
,但等待它抛出第一个InnerException
。
您需要的其他信息在任务中。WhenAll documentation(强调我的):
如果任何提供的任务在故障状态下完成,则返回的任务也将在故障状态下完成,其中其异常将包含来自每个提供的任务的未包装异常集的聚合。
使Task的异常看起来像:
AggregateException
NullReferenceException
ArgumentException