【问题标题】:How to get all exceptions from all nested tasks of async/awaited parent?如何从异步/等待父级的所有嵌套任务中获取所有异常?
【发布时间】:2013-05-12 23:32:56
【问题描述】:

重用稍作修改的代码from this answer,如何修改才能实现@svick's advice

但是如果您将任务保存到变量中并调用 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-blocks 内外都会产生错误:

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);
        }
    }
}

【问题讨论】:

  • 第一个AggregateException(来自原始任务)被包裹在第二个AggregateException(来自后续任务)中,因此您实际上需要调用Flatten()两次才能进入内部异常你想要的。
  • 抱歉,我删除了 Variant2。有一个愚蠢的错字。改正后Variant2开始输出预期结果

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


【解决方案1】:

这与Tasks 或async-await 无关。如果您将代码简化为以下代码,您仍然会得到相同的错误:

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

编译器假定try 内可能会引发异常,但在执行分配之前,因此您会收到此错误。为什么编译器会这样假设?因为它实际上可能发生:ThreadAbortException 几乎可以在任何时候抛出。并且关于明确赋值的规则不要试图太聪明以至于不知道可以抛出特定异常的规则是什么。

要解决此问题,请将 null(或其他默认值)分配给变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    • 2015-09-19
    • 2018-07-07
    • 2016-01-15
    • 2021-03-15
    • 1970-01-01
    相关资源
    最近更新 更多