百密一疏的Bug很難避免,沒有誰能保證,我的程序永遠 0 BUG;
突然接手一個很龐大的項目,在項目運行期間會莫名異常結束,異常極難重現,還找不出BUG代碼,代碼太多了。
這個時候就需要把程序中發生的BUG記錄下來,知道哪里BUG了,才好下次更新解決。
把所有代碼全部加 try catch ? 那就懷孕了,真的搞大了。
未捕獲的異常處理:
一:C# 在 Application 類中提供了 DispatcherUnhandledException 事件,用於處理UI線程上未捕獲的異常
App.Current.DispatcherUnhandledException += App_DispatcherUnhandledException;
void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
//e.Exception 發生的異常
//e.Handled 是否已處理異常事件
}
但是 DispatcherUnhandledException 捕獲不了 非UI線程上發生的異常
二:C# 在 AppDomain 類中提供了 UnhandledException 事件,用於捕獲應用程序域中發生的異常
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { MessageBox.Show("Unhandle"); //MessageBox.Show((e.ExceptionObject == null ? "Null" : e.ExceptionObject.GetType().Name), // "CurrentDomain_UnhandledException:"); }
這樣就能捕獲應用程序域中發生的異常,當然,包括UI線程和非UI線程異常,如果你有創建應用程序域的需求,創建完成,再綁定下事件即可。
但是AppDomain.UnhandledException 事件沒有提供 終止異常,也就是說,異常發生了,你沒捕獲,這里通知一下,但是該程序結束還得結束。
在這里要特別提到官方封裝的 Delegate.BeginInvoke();
"已知:"在異步函數中發生了異常並且沒處理:
"求解:"
1.沒調用 Delegate.EndInvoke() 函數:
終止執行。 程序不會掛掉,異常丟棄。這是種很隱蔽的BUG,很難發現。
AppDomain.UnhandledException 事件不會通知發生了異常,這里要特別注意。
public void Hello() { World(); Load(); } public void World() {
throw new Exception();
} public void Load() { MessageBox.Show("Suc"); } var action = new Action(Hello); action.BeginInvoke(null, null);
像這種示例,如果在World() 方法中發生了異常,線程會立即終止,Load() 函數就不會執行,程序也不會終止。
一個函數沒有執行,也許就會導致很嚴重的異常,還很難發現。
2.調用了 Delegate.EndInvoke() 函數:
異常拋出, 程序掛掉。
AppDomain.UnhandledException 事件會通知發生了異常
這里也許會有個需求,如果我想處理 AppDomain.UnhandledException 事件中的異常怎么辦?程序掛了太惡心了。
我們來繼續擴展這個框架
/// <summary> /// 委托 擴展類 /// </summary> public static class DelegateExtension {
/// <summary> /// 可以被捕獲異常的異步調用 /// </summary> /// <param name="dele"></param> public static void UnsafeBeginInvoke(this Delegate dele) { var action = new Action(() => { dele.DynamicInvoke(); }); action.BeginInvoke(new AsyncCallback((ar) => { try { action.EndInvoke(ar); } catch (Exception ex) { App.Current.Dispatcher.BeginInvoke(new Action(() => { throw ex; })); } }), null); } }
有點不倫不類哈,厄。把異常推送到UI線程上拋出,讓Application.DispatcherUnhandledException 事件處理
其它:C# 在 TaskScheduler 類中提供了 UnobservedTaskException 事件,用於捕獲 Task 異步異常.
