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进行处理。

