Bra*_*ann 9 .net c# exception winforms
我正在使用Application.ThreadException事件来处理和记录我的winforms应用程序中的意外异常.
现在,在我的应用程序的某个地方,我有以下代码(或者更确切地说是相同的东西,但这个虚拟代码足以重现我的问题):
try
{
throw new NullReferenceException("test");
}
catch (Exception ex)
{
throw new Exception("test2", ex);
}
Run Code Online (Sandbox Code Playgroud)
我显然希望我的Application_ThreadException处理程序能够传递"test2"异常,但情况并非总是这样.通常情况下,如果另一个线程将我的代码封送到UI,我的处理程序会收到"测试"异常,就像我根本没有抓到"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));
}
}
Run Code Online (Sandbox Code Playgroud)
我的计算机上该程序的输出是:
test
... here I click button1
test2
Run Code Online (Sandbox Code Playgroud)
我在.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();
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
这是一个异常.GetBaseException()调用,它会搞砸你的异常消息.为什么Windows窗体设计师选择这样做对我来说不是很清楚,参考源中的代码没有评论.我只能猜测没有它,异常将更难调试,以防它由Windows窗体管道代码而不是应用程序代码引发.不是很好的解释.
他们已经说过他们不会修复它,也许你可以添加你的投票.不要抱有希望.
解决方法是不设置InnerException.当然不是一个很好的选择.
异常#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();
}
...
}
Run Code Online (Sandbox Code Playgroud)