在另一个线程中抛出异常时未调用UnhandledException

本文关键字:调用 UnhandledException 抛出异常 另一个 线程 | 更新日期: 2023-09-27 18:08:20

根据Microsoft文档,当线程(来自线程池或使用System.Threading.Thread类创建)上发生未处理的异常时,AppDomain. thread . class="qnd">UnhandledException事件应该为应用程序的默认AppDomain触发。下面是MSDN链接,在第二个注释部分之后解释它。

但是我不能重现这种行为,据我所知,从我的测试应用程序中,它从来没有在默认的AppDomain或用于创建线程的AppDomain上触发UnhandledException。是文档错了还是我的测试代码错了?

using System;
using System.Runtime.ExceptionServices;
using System.Reflection;
public class Program
{
    static void Main()
    {
        Program.HookAppDomainExceptions();
        Test t = CreateTestInsideAppDomain("Nested1");
        t.SetupNested1();
        Console.ReadLine();
    }
    public static Test CreateTestInsideAppDomain(string appDomainName)
    {
        AppDomain nested1 = AppDomain.CreateDomain(appDomainName);
        string executingName = Assembly.GetExecutingAssembly().FullName;
        return (Test)nested1.CreateInstanceAndUnwrap(executingName, "Test");
    }
    public static void HookAppDomainExceptions()
    {
        AppDomain.CurrentDomain.FirstChanceException +=
            new EventHandler<FirstChanceExceptionEventArgs>(FirstChanceException);
        AppDomain.CurrentDomain.UnhandledException +=
            new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
    }
    public static void FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine("Domain:{0} FirstChanceException Handler",
                          AppDomain.CurrentDomain.FriendlyName);
    }
    public static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine("Domain:{0} UnhandledException Handler",
                          AppDomain.CurrentDomain.FriendlyName);
    }
}
public class Test : MarshalByRefObject
{
    private delegate void Nothing();
    public void SetupNested1()
    {
        var start = new Nothing(Nested1ThreadStart);
        start.BeginInvoke(null, null);
    }
    static void Nested1ThreadStart()
    {
        Program.HookAppDomainExceptions();
        Test t = Program.CreateTestInsideAppDomain("Nested2");
        t.SetupNested2();
    }
    public void SetupNested2()
    {
        Program.HookAppDomainExceptions();
        Test t = Program.CreateTestInsideAppDomain("Nested3");
        t.ThrowException();
    }
    public void ThrowException()
    {
        Program.HookAppDomainExceptions();
        throw new ApplicationException("Raise Exception");
    }
}

在另一个线程中抛出异常时未调用UnhandledException

在你的代码中,UnhandledException没有在任何AppDomain上被触发,因为如果你使用BeginInvoke()调用一个委托,在其执行期间抛出的任何异常都会被处理,然后在你调用EndInvoke()时被重新抛出,而你没有。

如果你调用EndInvoke():

start.EndInvoke(start.BeginInvoke(null, null));

或同步执行委托:

start();

您得到类似的结果:主域的UnhandledException被提升。

如果相反,您按照文档所说的,使用Thread类启动一个新线程:

new Thread(Nested1ThreadStart).Start();

Nested1UnhandledException和主应用程序域升高。

那么,回答你的问题:文档是正确的。你的代码错了。当您使用BeginInvoke()异步调用delegate时,您应该始终稍后调用EndInvoke()

我也有这个问题。我使用观察者模式来解决这个问题。你可以在你的调用者类中实现一个接口,它有一个方法,当发生异常时从另一个线程调用。

下面的链接展示了如何实现这个模式探索观察者设计模式