@坏坏Dong
在项目中遇到问题,在创建窗口句柄之前,不能在控件上调用Invoke或BeginInvoke的问题。在项目过程中,在Visual Studio中调试的时候,程序在运行过程中经常有这个错误,整个界面异常。且出错时间无规律,有时候几天没有错误,有时候运行频繁报错;且本界面运行的时候,会占用到CPU90%以上的资源,造成有时候界面很卡顿。
程序员经常说“「我爱你」三个字,讲出来只要三秒钟,解释要三小时,证明却要一辈子。「Bug」三个字母,发现需要三秒,找到需要三小时,Debug却要一辈子。”。就算是资深的程序员也会写出Bug,但Bug并不可怕,重要的是在Bug发生的时候迅速定位Bug。
和师兄请教问题的解决办法:
首先,我在主界面的线程和相关方法中在代码中加了try{}catch{}异常捕获,但是没有奏效;发现界面运行什么都不做,不执行任何操作,就会中断抛出异常,于是又尝试了以下的措施:
1.粗暴的在程序入口处添加异常捕捉
把这种异常捕获方法加到代码的方法中,可以捕捉出错的位置
try
{
}
catch (Exception ex)
{
MessageBox.Show("位置:" + "[" + ex.Source + "]" + "\r\n" + ex.StackTrace + "\r\n"
+ "信息:" + "[" + ex.GetType() + "]" + ex.Message, "ExceptionInfo");
}
//说明
//ex.Source 获取导致错误的应用对象的名称
//ex.StackTrace 异常堆栈,获取调用堆栈上的字符串表示形式
//ex.GetType() 获取错误的类型
捕获错误:
位置:[Separator]在 xxxx(定位到报错的函数位置)
显示错误的地方的详细信息(工程,目录,某个.cs代码 以及行号)
信息:获取错误类型并提示中文错误信息
2.全局异常捕获,捕获整个程序的异常
在program程序的入口处设置try……Catch,捕获异常
异常是通过Throw命令抛出,一路从抛出的模块里上抛,如果中途没有被try…catch…抓住的话就会一直抛到CLR(公共语言运行时)。如果用栈来描述这个过程的话,那就是异常会从栈的栈顶一路下沉,直到中途被try…catch…抓住或者直至沉到栈底,被CLR接住。CLR接收到异常之后的处理方式非常的简单粗暴——直接报错,然后关闭程序
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
catch (Exception ex)
{
MessageBox.Show("位置:" + "[" + ex.Source + "]" + "\r\n" + ex.StackTrace + "\r\n"
+ "信息:" + "[" + ex.GetType() + "]" + ex.Message, "ExceptionInfo");
}
全局异常捕获一下。整个程序的异常一下子捕获,不用一个一个加了,这种方法也不知道能不能捕获到子线程中的异常
3.事件监听 Application.ThreadException
Application类负责控制整个Windows 程序的运行, 用到一个Application类的一个事件:ThreadException
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandleException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private static void CurrentDomain_UnhandleException(object sender,UnhandledExceptionEventArgs e)
{
Exception ex = e.Exception;
MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace));
}
结果:失败了
4.子线程异常捕获 AppDomain.CurrentDomain.UnhandledException
可以通过监听Application.ThreadException事件来捕获程序异常,但这个Application.ThreadException事件只能捕获程序主线程上发生的异常。如果你用到了多线程,而且在子线程中发生了异常,不会触发Application.ThreadException事件的。如果要监听子线程的异常,我们就需要再注册一个事件:AppDomain.CurrentDomain.UnhandledException这个事件是在当前程序域内发生未处理异常时才会发生(如果没有监听Application.ThreadException事件的话,主线程异常最终也会触发这个事件)
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
//处理UI线程异常
Application.ThreadException += Application_ThreadException;
//处理非UI线程异常
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
//应用程序的主入口点
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FrmMain());
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}\r\nCLR即将退出:{3}", ex.GetType(), ex.Message, ex.StackTrace, e.IsTerminating));
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Exception ex = e.Exception;
MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace));
}
}
**我们需要注意的是注意这个:AppDomain.CurrentDomain.UnhandledException事件有一个事件参数叫UnhandledExceptionEventArgs e,它有一个bool类型的IsTerminating属性。这个属性指示了公共语言运行时(CLR)会不会因为本次异常而退出。如果这个属性是true的话,那么我们可以称这个错误是不可挽回的,就算我们监听到了这个事件,在这个事件的代码执行结束后,整个程序还是会崩溃退出的(因为我在VS里,所以被VS捕捉到了。)
用这种方法捕捉到异常了,
参考学习网址:
https://www.cnblogs.com/tomahawk/articles/5993874.html
https://www.cnblogs.com/wangshenhe/archive/2012/11/14/2769605.html
最后:
在Windows程序里,如果同时监听了Application.ThreadException事件和AppDomain.CurrentDomain.UnhandledException事件的话,则异常优先被Application.ThreadException事件捕获。但Application.ThreadException事件只能监听程序主线程抛出的异常。