为什么Dispatcher.BeginInvoke展开TargetInvocationException为的ThreadStart但不行动?但不、行动、BeginInvoke、Dispatcher

2023-09-03 03:48:39 作者:你真的走了。

考虑以下两种应用:

1

 公共部分类主窗口:窗口
{
    公共主窗口()
    {
        的InitializeComponent();
        this.Dispatcher.UnhandledException + = Dispatcher_UnhandledException;
    }

    无效Dispatcher_UnhandledException(对象发件人,DispatcherUnhandledExceptionEventArgs E)
    {
        System.Diagnostics.Debug.WriteLine(e.Exception.GetType());
    }

    私人无效Button_Click(对象发件人,RoutedEventArgs E)
    {
        this.Dispatcher.BeginInvoke((的ThreadStart)委托
        {
            抛出新AccessViolationException(测试);
        },DispatcherPriority.Input);
    }
}
 

2

 公共部分类主窗口:窗口
{
    公共主窗口()
    {
        的InitializeComponent();
        this.Dispatcher.UnhandledException + = Dispatcher_UnhandledException;
    }

    无效Dispatcher_UnhandledException(对象发件人,DispatcherUnhandledExceptionEventArgs E)
    {
        System.Diagnostics.Debug.WriteLine(e.Exception.GetType());
    }

    私人无效Button_Click(对象发件人,RoutedEventArgs E)
    {
        Dispatcher.BeginInvoke((行动)的委托
        {
            抛出新AccessViolationException(测试);
        },DispatcherPriority.Input);
    }
}
 

这两个应用程序不同的是使用两个不同的委托类型相同,动作的ThreadStart (具有相同签名虽然)。

结果(输出窗口,当你使用一键点击调用事件处理程序)

1:System.Reflection.TargetInvocationException

2:System.AccessViolationException

为什么应用程序的行为有什么区别?

完整的堆栈异常#1:

  System.Reflection.TargetInvocationException:艾因Aufrufziel帽子einen Ausnahmefehler verursacht。 ---> System.AccessViolationException:测试
   贝ExceptionTest.MainWindow< Button_Click> b__0()在C:\ Users \用户fschmitz \文档\ Visual Studio 11的\项目\ ExceptionTest \ MainWindow.xaml.cs:Zeile 40。
   ---恩德明镜internenAusnahmestapelüberwachung---
   贝System.RuntimeMethodHandle.InvokeMethod(对象的目标,对象[]参数,签名的签名,布尔构造函数)
   贝System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(obj对象,对象[]参数,对象[]参数)
   贝System.Delegate.DynamicInvokeImpl(对象[]参数)
   贝System.Windows.Threading.ExceptionWrapper.InternalRealCall(委托的回调,对象的args,的Int32 numArgs)
   贝MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(对象源,委托方法,对象的args,的Int32 numArgs,代表catchHandler)
 
为什么腾讯当年会和360展开3Q大战,却一味吞声忍气

解决方案

我认为罪魁祸首就在于在 InternalRealCall 的方法 ExceptionWrapper 。更具体地说,下面的部分,我们有动作代表特殊的套管。

 行动行动=回调的动作;
如果(动作!= NULL)
{
    行动();
}
其他
{
    // ...删除code ..
    物镜= callback.DynamicInvoke();
}
 

由于动作代表被直接调用产生的例外是一个你最初抛出。对于所有其他委托类型,因为调用经过反射的异常被包裹在一个 TargetInvocationException

在最后,差别是一个副作用与如何提供委托调用,直接或通过反射

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)

解决方案

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.

 
精彩推荐