为什么Dispatcher.BeginInvoke为ThreadStart解包TargetInvocationException而不为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
(虽然它们具有相同的签名)之外,两个应用程序都是相同的。
结果(输出窗口,当您使用按钮单击调用事件处理程序时)
1:System.Reflection.TargetInvocationException
2:System.AccessViolationException
为什么应用程序的行为不同?
例外#1的完整堆栈:
System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. ---> System.AccessViolationException: test bei ExceptionTest.MainWindow.
我认为罪魁祸首在于ExceptionWrapper
InternalRealCall
方法。 更具体地说,以下部分我们有Action
代表特别套装。
Action action = callback as Action; if (action != null) { action(); } else { // ... removed code .. obj = callback.DynamicInvoke(); }
由于Action
委托直接调用,因此产生的exception是您最初抛出的exception。 对于所有其他委托类型,由于调用通过reflection,exception包含在TargetInvocationException
。
总之,差异是与直接或通过反思调用所提供的代表的方式相关的副作用。