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

Phi*_*ght 8 c# clr exception .net-4.0

根据Microsoft文档,当线程(来自线程池或使用System.Threading.Thread类创建)发生未处理的异常时,应触发AppDomain.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");
    }
}
Run Code Online (Sandbox Code Playgroud)

svi*_*ick 11

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

如果你打电话EndInvoke():

start.EndInvoke(start.BeginInvoke(null, null));
Run Code Online (Sandbox Code Playgroud)

或同步执行委托:

start();
Run Code Online (Sandbox Code Playgroud)

您得到类似的结果:UnhandledException主域名被提出.

相反,如果您执行文档所说的内容并使用Thread该类启动新线程:

new Thread(Nested1ThreadStart).Start();
Run Code Online (Sandbox Code Playgroud)

UnhandledExceptionNested1和主要的应用领域被提出.

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

  • 我宁愿选择`start.BeginInvoke(iar => start.EndInvoke(iar),null)`因为你的用法使方法调用同步.不然,优秀的答案! (2认同)