一般情况下,调用Task的Wait(),WaitAny(),WaitAll(),或者等待Result即可捕获AggregateException异常
Task task = new Task(() =>
{
throw new Exception("异步方法发生异常!")
});
task.Start();
try
{
task.Wait();
}
catch(AggregateException ex)
{
//打印异常具体信息
}
但是在异步方法中使用Wait强制阻塞当前线程,只是为了捕获异常,这种迷之操作吾辈不屑之。思来想去,想到一个折中的方法,在Task的后续任务中捕获异常,客官请看:
Task task = new Task(() =>
{
throw new InvalidOperationException("并行任务中发生未知异常。");
});
task.Start();
Task endTsk = task.ContinueWith((task) =>
{
throw task.Exception;
},TaskContinuationOptions.OnlyOnFaulted);
try
{
endTsk.Wait();
}
catch(AggregateException ex)
{
foreach(var er in ex.InnerExceptions)
{
Console.WriteLine($"异常类型{er.InnerException.GetType()}\n" +
$"异常来源:{er.InnerException.Source}\n" +
$"异常内容:{er.InnerException.Message}");
}
}
Console.WriteLine("程序结束");
Console.ReadKey();
在后续任务中等待并捕获异常是一个能够接受的结果,而且等待的时间几乎可以忽略不计。
当然,作为攻城狮,对于完美代码的追求是不懈的,有没有更合理的方式呢?
回答是Yes,就是使用事件通知来进行异常捕获,如下所示:
public class AggregateExceptionArgs:EventArgs
{
public AggregateException Exception {get;set;}
}
public static event EventHandler<AggregateExceptionArgs> AggregateExceptionCatched;
static void Main(string[] args)
{
AggregateExceptionCatched += program_OnAggregateExcept;
Task.Run(() =>
{
try
{
throw new ArgumentException("task参数异常!");
}
catch (Exception ex)
{
AggregateExceptionArgs exArgs = new AggregateExceptionArgs
{
Exception = new AggregateException(ex)
};
AggregateExceptionCatched(null, exArgs);
}
});
}
static void program_OnAggregateExcept(Object sender, AggregateExceptionArgs ex)
{
foreach (var innEx in ex.Exception.InnerExceptions)
{
Console.WriteLine($"异常信息:{innEx.Message}");
}
}
以上例子中,我定义了一个事件参数AggregateExceptionArgs
,一个事件AggregateExceptionCatched
,在主线程中,我为事件定义了事件处理方法program_OnAggregateExcept
,当捕获到异常时,将调用处理方法。
这种方式完全不会阻塞当前线程,如果是在winForm或者WPF窗体应用程序中,还能将异常交付UI线程处理。因为墙裂推荐这种方式捕获异常。