在开发过程中我们一般都用try/catch块来捕获异常,但不是每个异常我们都能捕获,程序总会出现一些意想不到的情况,抛出一些未捕获的异常,这时就要用到全局异常捕获,即在程序的最外层加上捕获未处理异常,以免程序奔溃,影响用户体验。
事件 | 描述 |
---|---|
Application.DispatcherUnhandledException | UI线程的未处理异常捕获 |
AppDomain.UnhandledException | 非UI线程的未处理异常捕获 |
- 构造中添加注册事件
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
try
{
//设置应用程序处理异常方式:ThreadException处理
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
//UI线程的未处理异常捕获
Application.ThreadException += Application_ThreadException;
//非UI线程的未处理异常捕获
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
catch (Exception ex)
{
string str = ExceptionToString(ex, "主线程");
MessageBox.Show(str, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
- 提取异常信息函数
/// <summary>
/// 提取异常信息
/// </summary>
private static string ExceptionToString(Exception ex, string info)
{
StringBuilder str = new StringBuilder($"{DateTime.Now}, {info}发生了一个错误!{Environment.NewLine}");
if (ex.InnerException == null)
{
str.Append($"【对象名称】:{ex.Source}{Environment.NewLine}");
str.Append($"【异常类型】:{ex.GetType().Name}{Environment.NewLine}");
str.Append($"【详细信息】:{ex.Message}{Environment.NewLine}");
str.Append($"【堆栈调用】:{ex.StackTrace}");
}
else
{
str.Append($"【对象名称】:{ex.InnerException.Source}{Environment.NewLine}");
str.Append($"【异常类型】:{ex.InnerException.GetType().Name}{Environment.NewLine}");
str.Append($"【详细信息】:{ex.InnerException.Message}{Environment.NewLine}");
str.Append($"【堆栈调用】:{ex.InnerException.StackTrace}");
}
return str.ToString();
}
- UI线程未捕获异常处理函数
/// <summary>
/// UI线程未捕获异常处理函数
/// </summary>
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
try
{
string msg = ExceptionToString(e.Exception, "UI线程");
MessageBox.Show(msg, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (Exception ex)
{
string msg = ExceptionToString(ex, "UI线程 处理函数");
MessageBox.Show(msg, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
- 非UI子线程未捕获异常处理函数
/// <summary>
/// 非UI线程未捕获异常处理函数
/// </summary>
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
try
{
string msg;
if (e.ExceptionObject is Exception ex)
{
msg = ExceptionToString(ex, "非UI线程");
}
else
{
msg = $"发生了一个错误!信息:{e.ExceptionObject}";
}
MessageBox.Show(msg, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (Exception ex)
{
string msg = ExceptionToString(ex, "非UI线程 处理函数");
MessageBox.Show(msg, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
备注:子线程异常处理完成后程序还是会结束,如果不希望程序退出则在App.config中添加如下内容
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1"/>
</runtime>
</configuration>
这里的 <legacyUnhandledExceptionPolicy enabled=“1”/>,用意是使用早期版本的异常处理策略。