我有一个WinForm异步GUI应用程序,我在program.cs中设置了一些“全局”异常处理。我还有一个GUI线程正在执行“等待Task.WhenAll()”并捕获其异常并抛出等待的Task.Exception属性,以便AggregateException一直到program.cs中的异常处理程序(我想要迭代内部异常并记录它们)。
我可以看到从myAll()的try / catch中抛出的异常确实抛出了一个AggreateException,但是当我在program.cs中调试处理程序时,它不再是AggregateException - 它只是AggregateException的第一个Exception。 。我无法弄清楚是什么代码正在为我做这个“解缠”?
Program.cs中:
static void Main() {
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
...
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) {
if (e.Exception is AggregateException) {
// expect to log the contents of (e.Exception as AggregateException).Flatten().InnerExceptions, but exception coming
// in is not AggregateException but instead is
// ApplicationException("message 1")
}
else {
// handling for non aggregate exceptions
}
在Form1.cs中
private async void button1_Click(object sender, EventArgs e) {
Task overall = Task.WhenAll(
Task.Run(()=> { throw new ApplicationException("message 1"); }),
Task.Run(() => { throw new ApplicationException("message 2"); })
);
try {
await overall;
}
catch {
throw overall.Exception; // this is AggregateException
}
}
}
它不仅仅是AggregateException
- WinForms总是只会将GetBaseException()
发送给处理程序。也就是说,只有任何InnerException
链的最里面的例外。
显然这是一个longstanding WinForms bug,可能是永久性的。
您必须使用自己的类型解决它:
public class ExceptionWrapper : Exception
{
public new Exception InnerException { get; set; }
}
throw new ExceptionWrapper { InnerException = overall.Exception };
this issue最好的解决方法是通过AppDomain.FirstChangeException
事件捕获引发的异常,然后将此异常基本异常引用与Application.ThreadException
引发的异常进行比较。
像这样的东西:
private Exception lastFirstChanceException;
AppDomain.CurrentDomain.FirstChanceException += (sender, e) =>
{
lastFirstChanceException = e.Exception;
};
Application.ThreadException += (sender, e) =>
{
if (lastFirstChanceException?.GetBaseException() == e.Exception)
{
var realException = lastFirstChanceException; // This is the "real" exception thrown by some code
}
};