如何从异步/等待父级的所有嵌套任务中获取所有异常?

时间:2013-05-17 17:53:42

标签: c# exception-handling task-parallel-library async-await c#-5.0

重新使用稍加修改的代码from this answer,如何修改代码以实现@svick's advice

  

但是如果将Task保存到变量并调用   task.Exception.Flatten(),将返回两个异常

//C# console app
  class Program
  {
    static void Main(string[] args)
    {
      Test();
      Console.ReadLine();
    }
    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;
        foreach(Exception ex in containingTask.Exception
                                              .Flatten().InnerExceptions)
        //Possible 'System.NullReferenceException'
        { //never entered
            Console.WriteLine("@@@@@"+ex.GetType().Name);
        } 
      }//try
      catch (AggregateException ex)
      {
        Console.WriteLine("** {0} **", ex.GetType().Name);
        foreach (var exc in ex.Flatten().InnerExceptions)
        {
          Console.WriteLine("$$$$$$"+exc.GetType().Name);
        }

//foreach (Exception exxx in containingTask.Exception.Flatten().InnerExceptions)
//Use of unassigned local variable 'containingTask' 
      }
//foreach (Exception exxx in containingTask.Exception.Flatten().InnerExceptions)
////Use of unassigned local variable 'containingTask'   
    }
  }

当我尝试使用或不使用try- / catch-blocks访问containingTask.Exception.Flatten().InnerExceptions时,在try - ,catch - 块内或外,产生错误:

Use of unassigned local variable 'containingTask'   

Possible 'System.NullReferenceException'

如何从两个子任务中查看/获取两个例外?

更新

此部分已被删除,因为在纠正错字后,代码会产生预期结果

变体#2(C#控制台应用程序):
尝试从"Async - Handling multiple Exceptions"重现“变通方法”以查看所有子任务的所有异常:

class Program
{
    static void Main(string[] args)
    {
        Tst();
        Console.ReadLine();
    }
    async static Task Tst()
    {
        try
        {
            Task t= Task.Factory.StartNew
                (
                    () =>
                       {
                           Task.Factory.StartNew
                           (
                               () =>
                                  { throw new NullReferenceException(); }
                               ,TaskCreationOptions.AttachedToParent
                           );
                           Task.Factory.StartNew
                           (
                               () =>
                                   { throw new ArgumentException(); }
                                   , TaskCreationOptions.AttachedToParent
                           );
                       }
                );
            await t.ContinueWith
                    (
                        tsk =>
                          {
                              if (tsk.Exception != null)
                                   throw tsk.Exception;
                           }
                    );
        }
        catch (AggregateException ex)
        {
            foreach (var exc in ex.Flatten().InnerExceptions)
            {
                Console.WriteLine("** {0} **", exc.GetType().Name);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("## {0} ##", ex.GetType().Name);
        }
    }
}

1 个答案:

答案 0 :(得分:4)

这与Taskasync - await无关。如果您将代码简化为以下代码,则仍会出现相同的错误:

string s;
try
{
    s = "something";
}
catch (SomeException)
{
}
Console.WriteLine(s);

编译器假定try内部可能会抛出异常,但在执行赋值之前会出现此错误。为什么编译器会假设?因为它实际上可能发生:ThreadAbortException几乎可以抛出任何一点。关于明确赋值的规则并不会过于聪明,无法知道可以抛出特定异常的规则是什么。

要解决此问题,请为变量指定null(或其他默认值)。