1、UI線程異常:多線程
1)直接在主線程中的異常,直接用try……catch捕獲(若是你懷疑某個代碼會拋出異常)。異步
2)其它可能性:建議使用Application.ThreadException+Application.SetUnhandledException捕獲異常,並防止應用程序終止。函數
1 private void button1_Click(object sender, EventArgs e) 2 { 3 throw new Exception("UI異常拋出"); 4 }
在Program.cs入口函數中:spa
public class Program { /// <summary> /// 應用程序的主入口點。 /// </summary> [STAThread] static void Main() { Application.ThreadException += Application_ThreadException; Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Form1 f1 = new Form1(); Application.Run(f1); } private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) { using (var f = File.AppendText("c:\\error2.txt")) { f.WriteLine(e.Exception.Message); } } }
點擊按鈕,會拋出異常(UI異常)。被寫入日誌,程序能夠繼續運行。線程
2、Task異常捕獲:日誌
1)使用Wait捕獲(由於Wait會把Task異常放入到主線程,因此主線程能夠捕獲)。code
注意,使用Wait捕獲的異常不是Exception而是AggregateException,其中能夠得到InnerExceptions,使用foreach的Exception遍歷:orm
try { Task.Factory.StartNew(() => { throw new Exception("人工建立的線程異常"); }).Wait(); } catch (AggregateException ex) { foreach (var item in ex.Flatten().InnerExceptions) { //在這裏處理你的異常 } }
2)在Task內部處理(推薦)blog
Task.Factory.StartNew(() => { try { } catch (Exception e) { } }).Wait();
3)使用Continue方法處理:it
Task.Factory.StartNew(() => { throw new Exception("人工建立的線程異常"); }).ContinueWith(t => t.Exception.Flatten()……);
4)當使用await(異步的時候),直接在GUI線程try……catch……捕獲異常(像普通代碼同樣,什麼異常就catch什麼異常)。
5)全部Task的異常(沒有使用await或者Wait,純多線程異常,內部也沒有處理過)會在Task被Finailize以後被主線程捕獲,拋出異常並終止主程序。此時應該在WinForm(Console控制檯在Main入口函數中),使用TaskSchedule.UnobservedTaskException:
namespace CSharpWinForm { public partial class Form1 : Form { public Form1() { InitializeComponent(); TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; } private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) { using (var f = File.AppendText("c:\\error.txt")) { foreach (var item in e.Exception.Flatten().InnerExceptions) { f.WriteLine("Task異常:"+item.Message); } } e.SetObserved(); } private void button1_Click(object sender, EventArgs e) { Task.Factory.StartNew(() => { throw new Exception("人工建立的線程異常"); }); Thread.Sleep(500); GC.Collect(); GC.WaitForPendingFinalizers(); } } }
3)Thread和ThreadPool的異常:
此異常會致使主程序崩潰,必須使用內部try……catch捕獲。固然,咱們能夠使用AppDomain.CurrentDomain的UnhandledException捕獲(可是沒法取消異常,仍然會有此異常):
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Thread th = new Thread(() => { throw new Exception("異常"); }); th.Start(); } }
public class Program { /// <summary> /// 應用程序的主入口點。 /// </summary> [STAThread] static void Main() { AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Form1 f1 = new Form1(); Application.Run(f1); } private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { using (var f = File.AppendText("c:\\error2.txt")) { f.WriteLine(e.ExceptionObject.ToString()); } } }