非常奇怪的Application.ThreadException行为
我正在使用Application.ThreadException事件来处理和记录我的winforms应用程序中的意外exception。
现在,在我的应用程序的某个地方,我有以下代码(或者更确切地说是相同的东西,但这个虚拟代码足以重现我的问题):
try { throw new NullReferenceException("test"); } catch (Exception ex) { throw new Exception("test2", ex); }
我显然希望我的Application_ThreadException处理程序能够传递“test2”exception,但情况并非总是这样。 通常情况下, 如果另一个线程将我的代码编组到UI,我的处理程序会收到“测试”exception,就像我根本没有抓到“test”一样。
以下是重现此行为的简短示例。 我省略了设计师的代码。
static class Program { [STAThread] static void Main() { Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); //Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); // has no impact in this scenario, can be commented. AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { //this handler is never called } static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { Console.WriteLine(e.Exception.Message); } } public partial class Form1 : Form { public Form1() { InitializeComponent(); button1.Click+=new EventHandler(button1_Click); } protected override void OnLoad(EventArgs e) { System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(ThrowEx)); t.Start(); } private void button1_Click(object sender, EventArgs e) { try { throw new NullReferenceException("test"); } catch (Exception ex) { throw new Exception("test2", ex); } } void ThrowEx() { this.BeginInvoke(new EventHandler(button1_Click)); } }
我的计算机上该程序的输出是:
test ... here I click button1 test2
我在.net 2.0,3.5和4.0上重现了这个。 有人有合理的解释吗?
您的代码中存在一个错误,使得调试正在进行的操作变得很困难:在创建表单的句柄之前启动该线程。 这将使BeginInvoke失败。 固定:
protected override void OnLoad(EventArgs e) { System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(ThrowEx)); t.Start(); }
Anyhoo,这是设计行为。 运行BeginInvoke目标的Windows窗体代码如下所示:
try { this.InvokeMarshaledCallback(tme); } catch (Exception exception) { tme.exception = exception.GetBaseException(); } ... if ((!NativeWindow.WndProcShouldBeDebuggable && (tme.exception != null)) && !tme.synchronous) { Application.OnThreadException(tme.exception); }
这是一个exception.GetBaseException()调用,它会搞砸你的exception消息。 为什么Windows窗体设计师选择这样做对我来说不是很清楚,参考源中的代码没有评论。 我只能猜测,如果没有它,exception将更难调试,以防它由Windows窗体管道代码而不是应用程序代码引发。 不是很好的解释。
他们已经说过他们不会解决它 ,也许你可以添加你的投票。 不要抱有希望。
解决方法是不设置InnerException。 当然不是一个很好的选择。
exception#1:在创建窗口句柄之前,无法在控件上Invoke
或BeginInvoke
。
所以,不要试图从构造函数调用。 在OnLoad()
:
public partial class Form1 : Form { public Form1() { InitializeComponent(); this.Load += new EventHandler(Form1_Load); button1.Click += new EventHandler(button1_Click); } private void Form1_Load(object sender, EventArgs e) { System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(ThrowEx)); t.Start(); } ... }
你必须打电话
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
首先在你的Main()方法中。
上述就是C#学习教程:非常奇怪的Application.ThreadException行为分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/999974.html