c# - 防止出现未处理的异常对话框

标签 c# .net exception

首先让我说我已经阅读了this useful article彻底并正在使用 CodeProject 的 SafeThread 类。无论是使用 Thread 还是 SafeThread,我都会得到相同的结果。

我已将我的问题简化为一个由两个表单组成的应用程序,每个表单都有一个按钮。主程序显示一个表单。当您单击该按钮时,将启动一个显示第二个表单的新线程。当您单击第二个表单上的按钮时,它在内部只是“抛出新的异常()”

当我在 VS2008 下运行它时,我看到“DoRun() 中的异常”。

当我在 VS2008 之外运行时,出现一个对话框“您的应用程序中发生了未处理的异常。如果您单击继续,应用程序......”

我尝试将 app.config 中的 legacyUnhandledExceptionPolicy 设置为 1 和 0。

当不在 VS2008 下运行时,我需要做什么来捕获第二个表单中抛出的异常?

这是我的 Program.cs

    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.ThreadException += new ThreadExceptionEventHandler    (Application_ThreadException);
            Application.SetUnhandledExceptionMode    (UnhandledExceptionMode.CatchException);
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            try
            {
               Application.Run(new Form1());
            }
            catch(Exception ex)
            {
                MessageBox.Show("Main exception");
            }                
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            MessageBox.Show("CurrentDomain_UnhandledException");
        }

        static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            MessageBox.Show("Application_ThreadException");
        }
    }

这是 Form1:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        SafeThread t = new SafeThread(new SimpleDelegate(ThreadMain));
        try
        {
            t.ShouldReportThreadAbort = true;
            t.ThreadException += new ThreadThrewExceptionHandler(t_ThreadException);
            t.ThreadCompleted += new ThreadCompletedHandler(t_ThreadCompleted);
            t.Start();
        }
        catch(Exception ex)
        {
            MessageBox.Show(string.Format("Caught externally! {0}", ex.Message));

        }
    }

    void t_ThreadCompleted(SafeThread thrd, bool hadException, Exception ex)
    {
        MessageBox.Show("t_ThreadCompleted");
    }

    void t_ThreadException(SafeThread thrd, Exception ex)
    {
        MessageBox.Show(string.Format("Caught in safe thread! {0}", ex.Message));
    }

    void ThreadMain()
    {
        try
        {
            DoRun();
        }
        catch (Exception ex)
        {
            MessageBox.Show(string.Format("Caught! {0}", ex.Message));
        }
    }

    private void DoRun()
    {
        try
        {
            Form2 f = new Form2();
            f.Show();
            while (!f.IsClosed)
            {
                Thread.Sleep(1);
                Application.DoEvents();
            }
        }
        catch(Exception ex)
        {
            MessageBox.Show("Exception in DoRun()");
        }
    }
}

这是 Form2:

public partial class Form2 : Form
{
    public bool IsClosed { get; private set; }

    public Form2()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        throw new Exception("INTERNAL EXCEPTION");
    }

    protected override void OnClosed(EventArgs e)
    {
        IsClosed = true;
    }
}

最佳答案

如果您确实希望在单独的 UI 线程(而不是 ShowDialog())上打开第二个表单以捕获异常并将其发送到您的 Application_ThreadException 方法,您需要确保第二个线程也设置为 CatchException 并且您需要订阅 Application.ThreadException 在该线程上 也是。这两个都是特定于线程的(并且有点古怪)。

您可以通过调用设置默认的“未处理的异常模式”:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, false);

这会将您创建的任何 UI 线程的应用程序范围模式设置为 CatchException。 (但在 Visual Studio 调试器和其他一些情况下运行时,此调用会失败。)或者,您的新 UI 线程可以使用通常的调用设置自己的模式(与将 true 传递给此重载相同)。

无论哪种方式,新的 UI 线程还需要订阅 Application.ThreadException 事件本身,因为订阅者存储在 [ThreadStatic] 变量中。

Application.ThreadException += Program.Application_ThreadException;

或者它可以使用单独的处理程序而不是路由到同一个处理程序,如果这有帮助的话。

我不确定这与使用 SafeThread 来完成它有何交叉,但我认为如果对第二个 UI 线程正确完成,就没有必要使用 安全线程。这很像您在主 UI 线程上执行此操作。

另请参阅我对 this question 的回答了解更多关于这些东西的怪癖。

关于c# - 防止出现未处理的异常对话框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1105573/

相关文章:

c# - .NET Core 2 中的 ReadAsMultipartAsync 等价物

java - XPathExpression.evaluate 何时抛出?

c# - 在 C# 中,你能找到你的计算机使用的代理服务器吗?

c# - 应用程序起点上的 StackOverFlow

.net - 何时设置 HttpContext.User.Identity?

iOS CALayerInvalidGeometry

c++ - 如何处理这个异常

c# - 如何证明返回 IEnumerable 的方法被调用了两次?

c# - Code-First 应用程序中的 XML 列

c# - Newtonsoft.Json CustomContractResolver 排除空对象节点