为什么Dispatcher.BeginInvoke为ThreadStart解包TargetInvocationException而不为Action解包?

时间:2015-02-26 14:47:52

标签: c# .net exception-handling begininvoke

考虑以下两个应用程序:

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);
    }
}

除了使用两种不同的委托类型ActionThreadStart(虽然它们具有相同的签名)之外,两个应用程序都是相同的。

结果(输出窗口,当您使用按钮单击调用事件处理程序时)

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)

1 个答案:

答案 0 :(得分:4)

我认为罪魁祸首在于InternalRealCall的{​​{1}}方法。更具体地说,以下部分我们有ExceptionWrapper个代表特别加入。

Action

由于直接调用Action action = callback as Action; if (action != null) { action(); } else { // ... removed code .. obj = callback.DynamicInvoke(); } 个委托,因此产生的异常是您最初抛出的异常。对于所有其他委托类型,由于调用通过反射,异常包含在Action中。

总之,差异是与直接或通过反思调用所提供的代表的方式相关的副作用。