根据Microsoft文档,当线程(来自线程池或使用System.Threading.Thread类创建)发生未处理的异常时,应触发AppDomain.UnhandledException事件以获取应用程序的默认AppDomain。以下是MSDN link,它在第二个注释部分后解释了它。
但我无法重现这种行为,据我所知,从我的测试应用程序中它永远不会在默认的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");
}
}
答案 0 :(得分:11)
在您的代码中UnhandledException
未在任何AppDomain
上触发,因为如果使用BeginInvoke()
调用委托,则在执行期间抛出的任何异常都会被处理,然后在以后重新引发你打电话给EndInvoke()
,你不打电话。
如果您致电EndInvoke()
:
start.EndInvoke(start.BeginInvoke(null, null));
或同步执行委托:
start();
您会得到类似的结果:主域名UnhandledException
被提升。
相反,如果您执行文档说明并使用Thread
类启动新线程:
new Thread(Nested1ThreadStart).Start();
<{1}} UnhandledException
Nested1
并且主要应用域名被提升。
所以,回答你的问题:文件是正确的。你的代码错了。使用BeginInvoke()
异步调用委托时,应始终稍后调用EndInvoke()
。
答案 1 :(得分:-1)
我也有这个问题。我使用观察者模式来解决这个问题。 你可以在你的调用者类中实现一个接口,该接口有一个方法,当发生异常时从另一个线程调用它。
这是一个链接,显示如何实现此模式Exploring the Observer Design Pattern