为什么 Dispatcher.BeginInvoke 为 ThreadStart 解包 TargetInvocationException 而不是为 Action 解包?
Why does Dispatcher.BeginInvoke unwrap TargetInvocationException for ThreadStart but not for Action?
考虑以下两个应用程序:
1:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
}
void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.Exception.GetType());
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Dispatcher.BeginInvoke((ThreadStart)delegate
{
throw new AccessViolationException("test");
}, DispatcherPriority.Input);
}
}
2:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
}
void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.Exception.GetType());
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke((Action)delegate
{
throw new AccessViolationException("test");
}, DispatcherPriority.Input);
}
}
除了使用两种不同的委托类型 Action
和 ThreadStart
(尽管它们具有相同的签名)之外,这两个应用程序是相同的。
结果(输出 window,当您使用按钮单击调用事件处理程序时)
1: System.Reflection.TargetInvocationException
2: System.AccessViolationException
为什么应用程序的行为不同?
异常 #1 的完整堆栈:
System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. ---> System.AccessViolationException: test
bei ExceptionTest.MainWindow.<Button_Click>b__0() in c:\Users\fschmitz\Documents\Visual Studio 11\Projects\ExceptionTest\MainWindow.xaml.cs:Zeile 40.
--- Ende der internen Ausnahmestapelüberwachung ---
bei System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
bei System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
bei System.Delegate.DynamicInvokeImpl(Object[] args)
bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
bei MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
我认为罪魁祸首在于 ExceptionWrapper
的 InternalRealCall
方法。更具体地说,我们有 Action
代表特殊情况的以下部分。
Action action = callback as Action;
if (action != null)
{
action();
}
else
{
// ... removed code ..
obj = callback.DynamicInvoke();
}
由于 Action
委托被直接调用,因此产生的异常就是您最初抛出的异常。对于所有其他委托类型,由于调用是通过反射进行的,因此异常被包装在 TargetInvocationException
.
中
总而言之,差异是与如何直接或通过反射调用提供的委托相关的副作用。
考虑以下两个应用程序:
1:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
}
void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.Exception.GetType());
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Dispatcher.BeginInvoke((ThreadStart)delegate
{
throw new AccessViolationException("test");
}, DispatcherPriority.Input);
}
}
2:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
}
void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.Exception.GetType());
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke((Action)delegate
{
throw new AccessViolationException("test");
}, DispatcherPriority.Input);
}
}
除了使用两种不同的委托类型 Action
和 ThreadStart
(尽管它们具有相同的签名)之外,这两个应用程序是相同的。
结果(输出 window,当您使用按钮单击调用事件处理程序时)
1: System.Reflection.TargetInvocationException
2: System.AccessViolationException
为什么应用程序的行为不同?
异常 #1 的完整堆栈:
System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. ---> System.AccessViolationException: test
bei ExceptionTest.MainWindow.<Button_Click>b__0() in c:\Users\fschmitz\Documents\Visual Studio 11\Projects\ExceptionTest\MainWindow.xaml.cs:Zeile 40.
--- Ende der internen Ausnahmestapelüberwachung ---
bei System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
bei System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
bei System.Delegate.DynamicInvokeImpl(Object[] args)
bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
bei MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
我认为罪魁祸首在于 ExceptionWrapper
的 InternalRealCall
方法。更具体地说,我们有 Action
代表特殊情况的以下部分。
Action action = callback as Action;
if (action != null)
{
action();
}
else
{
// ... removed code ..
obj = callback.DynamicInvoke();
}
由于 Action
委托被直接调用,因此产生的异常就是您最初抛出的异常。对于所有其他委托类型,由于调用是通过反射进行的,因此异常被包装在 TargetInvocationException
.
总而言之,差异是与如何直接或通过反射调用提供的委托相关的副作用。