一般情況下,調用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線程處理。因為牆裂推薦這種方式捕獲異常。
