Why does Dispatcher.BeginInvoke unwrap TargetInvocationException for ThreadStart but not for Action?

蹲街弑〆低调 提交于 2019-12-01 05:15:32

问题


Consider the following two applications:

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

Both applications are identical except for using two different delegate types, Action and ThreadStart(which have the same signature though).

Results (output window, when you invoke the event handler using a button click)

1: System.Reflection.TargetInvocationException

2: System.AccessViolationException

Why do the applications differ in behaviour?

Full stack for exception #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:


I think the culprit lies within InternalRealCall method of ExceptionWrapper. More specifically the following part where we have Action delegates special cased.

Action action = callback as Action;
if (action != null)
{
    action();
}
else
{
    // ... removed code ..
    obj = callback.DynamicInvoke();
}

Since Action delegates are called directly the resulting exception is the one you originally thrown. For all other delegate types, since the invocation goes through reflection the exception is wrapped in a TargetInvocationException.

In conclusion, the differences is a side-effect related to how the provided delegate is called, directly or through reflection.



来源:https://stackoverflow.com/questions/28745420/why-does-dispatcher-begininvoke-unwrap-targetinvocationexception-for-threadstart

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!