C# 非常奇怪的Application.ThreadException行为

C# 非常奇怪的Application.ThreadException行为,c#,.net,winforms,exception,C#,.net,Winforms,Exception,我正在使用该事件处理和记录winforms应用程序中的意外异常 现在,在我的应用程序中的某个地方,我得到了以下代码(或者更确切地说是等效的代码,但是这个伪代码足以重现我的问题): 很明显,我希望我的应用程序线程异常处理程序传递“test2”异常,但情况并非总是如此。通常,如果另一个线程将我的代码封送到UI,我的处理程序会收到“测试”异常,就像我根本没有捕获到“测试”一样。 下面是一个复制这种行为的简短示例。我省略了设计师的代码 static class Program { [S

我正在使用该事件处理和记录winforms应用程序中的意外异常

现在,在我的应用程序中的某个地方,我得到了以下代码(或者更确切地说是等效的代码,但是这个伪代码足以重现我的问题):

很明显,我希望我的应用程序线程异常处理程序传递“test2”异常,但情况并非总是如此。通常,如果另一个线程将我的代码封送到UI,我的处理程序会收到“测试”异常,就像我根本没有捕获到“测试”一样。

下面是一个复制这种行为的简短示例。我省略了设计师的代码

     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
我在.NET2.0、3.5和4.0上复制了这个。有人有逻辑解释吗?

异常#1:
调用
开始调用
在创建窗口句柄之前不能对控件进行调用

因此,不要试图从构造函数调用。在
OnLoad()中执行此操作。

你必须打电话

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)


首先在Main()方法中。

代码中有一个bug使得调试发生的事情变得困难:在创建窗体句柄之前启动线程。这将使BeginInvoke失败。修正:

    protected override void OnLoad(EventArgs e) {
        System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(ThrowEx));
        t.Start();
    }
总之,这是设计的行为。运行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()调用弄乱了异常消息。Windows窗体设计人员选择这样做的原因我不太清楚,参考源代码中没有对代码的注释。我只能猜测,如果没有它,异常将更难调试,因为它是由Windows窗体管道代码而不是应用程序代码引发的。这不是一个很好的解释

他们已经说过,也许你可以投你一票。不要抱太大希望


解决方法是不设置InnerException。当然不是一个好的选择。

你的建议很有道理,但这并不能改变奇怪的行为。@Brann,你是对的。这种奇怪的行为仍然存在。但是,我没有在按钮单击处理程序中执行
catch(Exception ex)
,而只是执行
catch
,从而纠正了这个问题。非常有趣。异常未被释放,并且引发异常。
GetBaseException
调用旨在从
Invoke
打开
targetingException
s。不是这样的。Control.BeginInvoke()与Delegate.BeginInvoke()完全不同。例如,它不会将异常封送回调用方。
    protected override void OnLoad(EventArgs e) {
        System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(ThrowEx));
        t.Start();
    }
  try
  {
      this.InvokeMarshaledCallback(tme);
  }
  catch (Exception exception)
  {
      tme.exception = exception.GetBaseException();
  }
  ...
       if ((!NativeWindow.WndProcShouldBeDebuggable && (tme.exception != null)) && !tme.synchronous)
       {
           Application.OnThreadException(tme.exception);
       }