为什么AppDomain异常总是终止应用程序?

时间:2009-08-19 17:04:44

标签: .net exception-handling thread-exceptions

这与previous question

有关

我现在想要了解的是如何阻止UI线程异常终止应用程序,而非UI异常则不能。

供参考,请参阅this example

最重要的是,在这种情况下,我希望能够“静默地”终止进程 - 不显示Windows对话框,询问我是否要发送错误报告。

这是我的AppDomain UnhandledExceptionHandler:

private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{            
    try
    {
        // Maybe do some logging here if allowed
    }
    catch
    {
    }

    // then just terminate the application
    Application.Exit();            
}

更新
根据{{​​3}}中的评论,我想澄清一点,最重要的是,我想了解更多关于使UI线程尽早通过{{1来捕获未处理的异常的机制的机制。机制。是否可以在非UI线程上实现此类行为。

3 个答案:

答案 0 :(得分:8)

在Google上进行了一些搜索之后,我发现这个非常有趣的解释是针对Jeff Atwood on his blog描述的同一问题。

  

大家好,   对困惑感到抱歉。这种行为实际上就是设计,虽然设计有时会有点复杂。

     

首先要理解的是UnhandledException事件不是未处理的异常“处理程序”。 注册活动,与文档说的相反:-(,不会导致处理未处理的异常。(从那时起他们就不会被处理,但我会停止循环推理已经......) UnhandledException事件只是通知你一个异常未处理,以防你想在线程或应用程序死亡之前尝试保存状态.FWIW,我已经提交了一个bug来获取文档已修复。

     

只是为了使事情复杂化,在v1.0和1.1中,未处理的异常并不总是意味着你的应用程序会死掉。如果未处理的异常发生在除主线程之外的任何其他线程或在非托管代码中开始生命的线程中,则CLR会使用异常并允许您的应用继续运行。这通常是邪恶的,因为经常发生的事情是,例如,ThreadPool线程会一个接一个地静静地消失,直到你的应用程序实际上没有做任何工作。弄清楚这种失败的原因几乎是不可能的。这可能就是Jeff之前认为它有效的原因......他总是在非主线程上看到崩溃。

     

在v2.0中,任何线程上的未处理异常都将取消该应用程序。我们发现,调试崩溃比调试挂起或上述静默停止工作问题要容易得多。

     

BTW,在我的1.1机器上,来自MSDN的示例确实具有预期的输出;只是在你连接调试器之后才显示第二行(或不是)。在v2中,我们已经翻转了一些东西,以便在调试器附加之前触发UnhandledException事件,这似乎是大多数人所期望的。

     

Jonathan Keljo   CLR异常PM   Jonathan Keljo于2005年2月18日下午10:02

但是,我仍然对UI线程如何完成允许你为所有UI线程异常拥有一个包罗万象的处理程序的技巧感兴趣。

更多,我对只为我的应用程序禁用.NET JIT调试对话框的方式非常感兴趣(没有disabling it for the whole machine as seen here

答案 1 :(得分:3)

并不是任何AppDomain异常终止了应用程序,而是未处理的异常(任何类型)将拆除AppDomain并终止应用程序。

这里的问题是你可以在相当高的层次上明确地处理UI线程异常。但是,当后台线程中存在未处理的异常时,无法在同一级别轻松处理它,因此它往往会传播并下拉应用程序。 Application.ThreadException允许您至少知道这是导致错误的原因,并在必要时记录它。

UI线程中未处理的异常将导致同样的事情发生。

答案 2 :(得分:2)

这有帮助吗?

Improved Unhandled Exception behavior in .NET 2.0

此外,这段代码似乎“安静地死”。你在找别的吗?

using System;

namespace UnhandledException
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;

            throw new NotImplementedException();
        }

        static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception exception = (Exception)e.ExceptionObject;
            System.Console.WriteLine("exception=[" + exception.ToString() + "]");

            Environment.Exit(-1);
        }   
    }
}