惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
V
V2EX
爱范儿
爱范儿
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
罗磊的独立博客
小众软件
小众软件
Vercel News
Vercel News
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
J
Java Code Geeks
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog
B
Blog
美团技术团队
量子位

博客园 - 张志敏

System.Net.Http for Silverlight 通过网页进行 iOS 应用内部分发 使用 Intel HAXM 为 Android 模拟器加速,媲美真机 Mono for Android 实现高效的导航 Activity 生命周期及其栈管理方式 我的第一个 Mono for Android 应用 谈谈 INotifyPropertyChanged 的实现 在 Silverlight 5 项目中使用 async/await NHibernate 关系映射中的 Formula 开源一个 Sliverlight 导航框架 SQLite 常用 SQL 让 VS 编译 MonoTouch 项目源文件不再出错 MonoTouch绑定CocoaTouch类库 升级 Xcode 4.3 后找不到 xcodebuild 的解决方法 iOS 静态类库项目的建立与使用 从源代码编译里程碑的 ICS ROM IIS 7.5 下应用程序池的预定义账户 Web API 依赖注入与扩展 ASP.NET Web API 简介
Task 编程中的异常处理
张志敏 · 2012-07-05 · via 博客园 - 张志敏

在 .Net 开发中, 使用 Task 、 Task<T> 进行异步编程是非常方便的, 但是在处理 Task 产生的异常时, 需要注意一个问题, 比如下面的代码:

static Task<int> TestAsync(int a, int b) {
   var tcs = new TaskCompletionSource<int>();
   Task.Factory.StartNew(() => {
      if (a + b < 0) {
         tcs.TrySetException(new InvalidOperationException("a + b < 0"));
      }
      else {
         tcs.TrySetResult(a + b);
      }
   });
   return tcs.Task;
}

当输入的两个参数之和小于 0 时, tcs 会设置一个 InvalidOperationException , 如果直接运行这段代码, 当这个函数返回的 Task 被 GC 回收时, 将会产生 AggregateException was unhandled 的异常, 运行代码如下:

static void Main(string[] args) {

   TestAsync(5, -10);

   Thread.Sleep(TimeSpan.FromMilliseconds(3000));

   GC.Collect();

   Console.WriteLine("Completed.");
}

当程序运行结束时, 会产生下图所示的异常:

2012-07-05_130006

关键的是这段文字:

A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

没有在等待 Task 完成时捕获其异常, 也没有读取 Task 的 Exception 属性, 结果导致异常被终结线程重新抛出。 也就是说, Task 异常有两种处理方式:

1、 调用 Task 的 Wait 方法时使用 try-catch 捕获异常:

var testTask = TestAsync(5, -10);
try {
   testTask.Wait();
}
catch(Exception ex) {
   Console.WriteLine(ex);
}

2、 在 Task 的 ContinueWith 方法中读取 Task 的 Exception 属性:

var testTask = TestAsync(5, -10);
testTask.ContinueWith(task => {
   if (task.IsFaulted) {
      Console.WriteLine(task.Exception.GetBaseException());
   }
   else {
      Console.WriteLine(task.Result);
   }
});

在 .Net 4.0 、 Sliverlight 5.0 、以及 MonoTouch 中均有类似的问题, 因此, 必须小心翼翼的处理 Task 产生的异常, 否则将会导致你的程序异常退出。