如何更好地了解“异步 - 处理多个异常”的代码/声明文章?(How to better unders

2019-09-03 11:17发布

运行下面的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 **

虽然,上面的代码被复制从第一个片段“异步-处理多个异常”博客文章,其中讲述了它:

下面的代码将捕获的单个的NullReferenceException或ArgumentException异常(在AggregateException将被忽略)

问题出在哪儿:

  1. 文章是错误的?
    哪个代码/报表,以及如何才能正确地理解它的变化?
  2. 我在再现文章的第一代码片段犯了一个错误?
  3. 这是由于在.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

所以,还评论说马特·史密斯 :

AggregateException被抓,只包含被抛出(或者是一个例外NullReferenceExceptionArgumentException取决于子任务的执行顺序)

最可能的是,文章仍然是正确的,或者至少是非常有用的。 我只需要了解如何更好地阅读/理解/使用

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生产或抓?

Answer 1:

这篇文章是错误的。 当你运行你的代码中, 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);
}


Answer 2:

在回答你的“更新2”的理由仍然是相同svick的答案。 该任务包含AggregateException ,但等待它抛出第一个InnerException

你需要额外的信息是Task.WhenAll文档(重点煤矿)在:

如果有任何的供应任务故障状态结束,返回的任务也将完成在故障状态,其中它的异常将包含一套从每个供应任务展开异常的聚集。

因此,该任务的例外看起来像:

AggregateException 
    NullReferenceException 
    ArgumentException


文章来源: How to better understand the code/statements from “Async - Handling multiple Exceptions” article?