posts - 930,  comments - 588,  views - 402万
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

     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   PetterLiu  阅读(722)  评论(0编辑  收藏  举报
编辑推荐:
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
阅读排行:
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
历史上的今天:
2011-01-27 .net中JSON序列化Object指定属性两种方法
点击右上角即可分享
微信分享提示