代码之家  ›  专栏  ›  技术社区  ›  floele

为什么Dispatcher.BeginInvoke为ThreadStart而不是Action打开TargetInvocationException?

  •  4
  • floele  · 技术社区  · 10 年前

    考虑以下两种应用:

    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.<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 回复  |  直到 10 年前
        1
  •  4
  •   João Angelo    10 年前

    我认为罪魁祸首就在里面 InternalRealCall 方法 ExceptionWrapper 。更具体地说,以下部分 Action 代表特殊情况。

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

    自从 行动 直接调用委托,生成的异常就是您最初抛出的异常。对于所有其他委托类型,由于调用经过反射,因此异常被包装在 TargetInvocationException .

    总之,这些差异是与如何直接或通过反射调用所提供的委托相关的副作用。