各类异常捕获
一、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入口函数中:
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异常)。被写入日志,程序可以继续运行。
二、Task异常捕获:
1)使用Wait捕获(因为Wait会把Task异常放入到主线程,所以主线程可以捕获)。
注意,使用Wait捕获的异常不是Exception而是AggregateException,其中可以获得InnerExceptions,使用foreach的Exception遍历:
try { Task.Factory.StartNew(() => { throw new Exception("人工创建的线程异常"); }).Wait(); } catch (AggregateException ex) { foreach (var item in ex.Flatten().InnerExceptions) { //在这里处理你的异常 } }
2)在Task内部处理(推荐)
Task.Factory.StartNew(() => { try { } catch (Exception e) { } }).Wait();
3)使用Continue方法处理:
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()); } } }