Task Parallel Library (TPL) 中,当你使用async/await 语法关键字时,你可能遇到以下异常处理的情况: Catch 块只会处理第一个异常而忽略其它的异常。来看下面代码块:

   1:          private static async void TestCatchExceptionWithTPL()
   2:          {
   3:              try
   4:              {
   5:                  await Task.Factory.StartNew(() =>
   6:                     {
   7:                         Task.Factory.StartNew(() =>
   8:                            { throw new NullReferenceException(); },
   9:                                 TaskCreationOptions.AttachedToParent);
  10:                         Task.Factory.StartNew(() =>
  11:                            { throw new ArgumentException(); },
  12:                                   TaskCreationOptions.AttachedToParent);
  13:                     });
  14:              }
  15:              catch (AggregateException aex)
  16:              {
  17:                  // this catch will never be target
  18:              }
  19:              catch (Exception ex)
  20:              {
  21:                  Console.WriteLine("## {0} ##", ex.GetType().Name);
  22:              }
  23:          }
 
执行上面的代码,有注意8,11行分别有两个Exception,而这时到第一个Catch块中AggregateException只会捕捉第一个NullReferenceException异常,这是By Design的问题。有个解决方案是这样的:

   1:              try
   2:              {
   3:                  Task t = Task.Factory.StartNew(() =>
   4:                      {
   5:                          Task.Factory.StartNew(() =>
   6:                            { throw new NullReferenceException(); },
   7:                                  TaskCreationOptions.AttachedToParent);
   8:                          Task.Factory.StartNew(() =>
   9:                            { throw new ArgumentException(); },
  10:                                 TaskCreationOptions.AttachedToParent);
  11:                      });
  12:                  await t.ContinueWith(tsk => { if (tsk.Exception != null) throw tsk.Exception; });
  13:              }
  14:              catch (AggregateException ex)
  15:              {
  16:                  foreach (var exc in ex.Flatten().InnerExceptions)
  17:                  {
  18:                      Console.WriteLine(exc.GetType().Name);
  19:                  }
  20:              }

 

注意上面12行代码,使用了CoutinueWith方法,为了让代码更加简洁了,我们可以写一个扩展方法:

        /// <summary>
        /// ThrowMultiple
        /// </summary>
        /// <param name="t">Task</param>
        /// <returns>Task type</returns>
        public static Task ThrowMultiple(this Task t)
        {
            return t.ContinueWith(tsk => { if (tsk.Exception != null) throw tsk.Exception; });
        }
 
        /// <summary>
        /// ThrowMultiple
        /// </summary>
        /// <typeparam name="T">Task this</typeparam>
        /// <param name="t">Task t</param>
        /// <returns>Task generic</returns>
        public static Task<T> ThrowMultiple<T>(this Task<T> t)
        {
            return t.ContinueWith(tsk =>
           {
               if (tsk.Exception != null)
                   throw tsk.Exception;
               return tsk.Result;
           });
        }


然后代码就是变成这样了:

   1:              try
   2:              {
   3:                  await Task.Factory.StartNew(() =>
   4:                     {
   5:                         Task.Factory.StartNew(() =>
   6:                            { throw new NullReferenceException(); },
   7:                                 TaskCreationOptions.AttachedToParent);
   8:                         Task.Factory.StartNew(() =>
   9:                            { throw new ArgumentException(); },
  10:                                   TaskCreationOptions.AttachedToParent);
  11:                     }).ThrowMultiple();
  12:              }
  13:              catch (AggregateException aex)
  14:              {
  15:                  // this catch will never be target
  16:              }
  17:              catch (Exception ex)
  18:              {
  19:                  Console.WriteLine("## {0} ##", ex.GetType().Name);
  20:              }


有看到上面代码11行的变化为我们扩展方法。就这么简单,以上代码在Vs2012下 .net framework 4.5 version 下测试通过,希望对你开发有帮助。

您可能感兴趣的文章:

Asp.net MVC 4 异步方法


作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog

posted on 2013-01-27 11:34  PetterLiu  阅读(722)  评论(0编辑  收藏  举报