C#4.0的并行库TPL,即Task(一)http://47.98.154.65/?id=1793
C#4.0的并行库TPL,即Task(二) http://47.98.154.65/?id=1798
C#4.0的并行库TPL,即Task(三) http://47.98.154.65/?id=1808
C#4.0的并行库TPL,即Task(四) http://47.98.154.65/?id=1815
C#4.0的并行库TPL,即Task(五) http://47.98.154.65/?id=1816
这一篇继续Task异常处理的话题:
代码:
下面的异常处理中,(1)(2)(3)演示了3种处理异常办法。这些地方都会断下来。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication20 { class Program { static void Main(string[] args) { // Get the task. var task = Task.Factory.StartNew<int>(() => { return div(32, 0); }); // For error handling. task.ContinueWith(t => { Console.WriteLine(t.Exception.Message); }, TaskContinuationOptions.OnlyOnFaulted); // If it succeeded. task.ContinueWith(t => { Console.WriteLine(t.Result); }, TaskContinuationOptions.OnlyOnRanToCompletion); task.ContinueWith(t => { if (t.Exception is AggregateException) { var ae = t.Exception as AggregateException; foreach (var e in ae.InnerExceptions) { Console.WriteLine(e.Message); //(1) } } }, TaskContinuationOptions.OnlyOnFaulted); task.ContinueWith((t) => { if (t.IsFaulted) { // (2) Exception ex = t.Exception; while (ex is AggregateException && ex.InnerException != null) ex = ex.InnerException; var s1=("Error: " + ex.Message); } else if (t.IsCanceled) { var s2=("Canclled."); } else { // completed successfully var s3=("Result: " + t.Result); } }); try { Console.WriteLine("result: " + task.Result); } catch (AggregateException aex) { aex.Flatten().Handle(ex => { // (3) Console.WriteLine(ex.Message); return true; }); } Console.ReadKey(); Console.WriteLine("Hello"); Console.ReadKey(); } private static int div(int x, int y) { if (y == 0) { throw new ArgumentException("y"); } return x / y; } } }
下面详细介绍一个3种处理方式:
(1)
自己处理 AggregateException
。这是从任务中抛出的,它是一个异常集合,可能包含得分多个异常,要求您检查内部异常以查找特定的异常。 像这样:
task.ContinueWith(t => { if (t.Exception is AggregateException) // is it an AggregateException? { var ae = t.Exception as AggregateException; foreach (var e in ae.InnerExceptions) // loop them and print their messages { Console.WriteLine(e.Message); // output is "y" .. because that's what you threw } } }, TaskContinuationOptions.OnlyOnFaulted);
(2)
这种方式是在具有.NET 4.0和VS2010的UI应用程序中如何执行此操作:
void Button_Click(object sender, EventArgs e) { Task.Factory.StartNew<int>(() => { return div(32, 0); }).ContinueWith((t) => { if (t.IsFaulted) { // faulted with exception Exception ex = t.Exception; while (ex is AggregateException && ex.InnerException != null) ex = ex.InnerException; MessageBox.Show("Error: " + ex.Message); } else if (t.IsCanceled) { // this should not happen // as you don't pass a CancellationToken into your task MessageBox.Show("Canclled."); } else { // completed successfully MessageBox.Show("Result: " + t.Result); } }, TaskScheduler.FromCurrentSynchronizationContext()); }
(3)
由于是task任务,因此应该获得AggregateException异常,该异常将包装在执行过程中发生的所有异常。 您会看到One or more errors occurred
消息,因为它是AggregateException.ToString()
方法的默认输出。
您需要异常实例的Handle方法。
另请参见此处处理此类异常的正确方法。
try { var t1 = Task.Delay(1000); var t2 = t1.ContinueWith(t => { Console.WriteLine("task 2"); throw new Exception("task 2 error"); }, TaskContinuationOptions.OnlyOnRanToCompletion); var t3 = t2.ContinueWith(_ => { Console.WriteLine("task 3"); return Task.Delay(1000); }, TaskContinuationOptions.OnlyOnRanToCompletion).Unwrap(); // The key is to await for all tasks rather than just // the first or last task. await Task.WhenAll(t1, t2, t3); } catch (AggregateException aex) { aex.Flatten().Handle(ex => { // handle your exceptions here Console.WriteLine(ex.Message); return true; }); }
其它处理方式:
try { mr[1].WaitOne(); TryExecuteTask(task); task.ContinueWith(t => (serialUnitCTS.Token), TaskContinuationOptions.OnlyOnFaulted); task.Wait(); } catch (AggregateException ex) { //AggregateException是task的异常集合 ex.Handle(predicate: e => { Console.WriteLine(e.Message); return true; }); } finally { }
另外在网上看到一个处理异常的技巧,摘录如下:
在async方法中,发生一个异常时,代码并不会直接跳到catch语句中去,而是继续执行,所以到最后catch语句中得到的错误信息是one or more exceptions occurs…
这样的设计给我们带来了麻烦就是传统的try/catch方法得到的无法得到具体的错误信息。
【解决方法】
在catch语句中记录错误信息
if (e is AggregateException) { AggregateException ae = (AggregateException)e; ae.Handle((x) => { exception = x.Message; return true; // Let anything else stop the application. }); } else { exception = e.Message; }
在 catch语句中取到AggregateException的信息(类似解决方法1),然后重新抛出一个带有具体错误信息的异常给调用者。
将异常转成AggregateException后,可以取到InnerException或者InnerExceptions, 然后再用解决方法1或者2进行处理。

