我在VS2005中运行的程序和直接运行可执行程序之间遇到了一个奇怪的区别.实质上,当在Application.DoEvents()
调用内的方法中抛出异常时,在Visual Studio中运行时可以捕获异常.运行已编译的可执行文件时,不会捕获异常并且程序崩溃.
这是一些简单的代码来演示这个问题.假设标准winforms样板和两个按钮和一个标签.
要运行此操作,请单击开始按钮以开始10秒计数.在10秒钟之前,按下中止按钮.并且会抛出异常DoEvents()
.应该抓住例外.这只发生在Visual Studio中运行时.
private void StartButton_Click(object sender, EventArgs e) { DateTime start = DateTime.Now; try { while (DateTime.Now - start < new TimeSpan(0, 0, 10)) { this.StatusLabel.Text = DateTime.Now.ToLongTimeString(); Application.DoEvents(); } MessageBox.Show("Completed with no interuption."); } catch (Exception) { MessageBox.Show("User aborted."); } } private void ButtonAbort_Click(object sender, EventArgs e) { throw new Exception("aborted"); }
我希望能够捕获这些异常.有没有办法使它工作?
更新:
我愿意考虑除了重新引入头痛的方法之外的其他方法DoEvents()
.但我还没有找到一个似乎更好的工作.我的情况是,我有一个长时间运行的循环,它控制着一些科学仪器,经常需要等待温度稳定或什么的.我想让我的用户能够中止进程,所以我有一个中止按钮,只是抛出一个自定义异常,我打算在最初启动进程的站点捕获.这似乎是一个完美的解决方案.除了由于某种原因它不起作用的事实.
如果无法实现这一点,那么有更好的方法吗?
更新2:
当我将它添加为Main()的第一行时,这使它作为可执行文件工作,但不在VS中,因此情况相反.疯狂的是,它似乎是一个无操作.我能理解这是怎么回事.
Application.ThreadException += delegate( object sender, System.Threading.ThreadExceptionEventArgs e ) { throw e.Exception; };
疯了吧.
你真的有使用DoEvents
?它导致重新进入,这可能很难调试.
我怀疑如果你从你的应用程序中删除重新入侵,你将能够更容易地找出在哪里捕获异常.
编辑:是的,肯定有更好的方法来做到这一点.在不同的线程上执行长时间运行的任务.UI线程应该只进行UI操作.使"中止"按钮设置一个标志,长时间运行的任务会定期检查.有关WinForms线程的示例,请参阅我的WinForms线程页面 ; 有关一个线程设置另一个线程要监视的标志的示例,请参见波动性页面.
编辑:我只记得BackgroundWorker
(我的文章没有涵盖 - 它是在.NET 2.0之前编写的)有一个CancelAsync
方法 - 基本上这个(用于CancellationPending
和WorkerSupportsCancellation
基本上处理"有一个标志设置取消"给你的东西.只需CancellationPending
从工作线程中检查,然后CancelAsync
从你的中止按钮点击处理程序调用.