What's the difference between InvokeAsync and BeginInvoke for WPF Dispatcher

前端 未结 4 861
庸人自扰
庸人自扰 2020-12-08 13:09

I noticed in .NET 4.5 that the WPF Dispatcher had gotten a new set of methods to execute stuff on the Dispatcher\'s thread called InvokeAsync. Before, .NET 4.5 we had Invoke

相关标签:
4条回答
  • 2020-12-08 13:13

    The exception handling is different.

    You may want to check the following:

    private async void OnClick(object sender, RoutedEventArgs e)
    {
        Dispatcher.UnhandledException += OnUnhandledException;
        try
        {
            await Dispatcher.BeginInvoke((Action)(Throw));
        }
        catch
        {
            // The exception is not handled here but in the unhandled exception handler.
            MessageBox.Show("Catched BeginInvoke.");
        }
    
        try
        {
           await Dispatcher.InvokeAsync((Action)Throw);
        }
        catch
        {
            MessageBox.Show("Catched InvokeAsync.");
        }
    }
    
    private void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        MessageBox.Show("Catched UnhandledException");
    }
    
    private void Throw()
    {
        throw new Exception();
    }
    
    0 讨论(0)
  • 2020-12-08 13:16

    There are no differences as the BeginInvoke method calls a private LegacyBeginInvokeImpl method which itslef calls the private method InvokeAsyncImpl (the method used by InvokeAsync). So it's basically the same thing. It seems like it's a simple refactoring, however it's strange the BeginInvoke methods weren't flagged as obsolete.

    BeginInvoke :

    public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method)
    {
        return this.LegacyBeginInvokeImpl(priority, method, null, 0);
    }
    
    private DispatcherOperation LegacyBeginInvokeImpl(DispatcherPriority priority, Delegate method, object args, int numArgs)
    {
        Dispatcher.ValidatePriority(priority, "priority");
        if (method == null)
        {
            throw new ArgumentNullException("method");
        }
        DispatcherOperation dispatcherOperation = new DispatcherOperation(this, method, priority, args, numArgs);
        this.InvokeAsyncImpl(dispatcherOperation, CancellationToken.None);
        return dispatcherOperation;
    }
    

    InvokeAsync :

    public DispatcherOperation InvokeAsync(Action callback, DispatcherPriority priority)
    {
        return this.InvokeAsync(callback, priority, CancellationToken.None);
    }
    
    public DispatcherOperation InvokeAsync(Action callback, DispatcherPriority priority, CancellationToken cancellationToken)
    {
        if (callback == null)
        {
            throw new ArgumentNullException("callback");
        }
        Dispatcher.ValidatePriority(priority, "priority");
        DispatcherOperation dispatcherOperation = new DispatcherOperation(this, priority, callback);
        this.InvokeAsyncImpl(dispatcherOperation, cancellationToken);
        return dispatcherOperation;
    }
    
    0 讨论(0)
  • 2020-12-08 13:21

    Well, one difference I've noticed is that InvokeAsync has a generic overload that returns a DispatcherOperation as a return value and accepts a Func as its delegate input parameter. Thus, you can retrieve the result of the operation via InvokeAsync in a type-safe way analogous to how you can await the result of a Task.

    0 讨论(0)
  • 2020-12-08 13:37

    There is a difference in method signature:

    BeginInvoke(Delegate, Object[])
    InvokeAsync(Action)
    

    For BeginInvoke() compiler creates array Object[] implicitly while for InvokeAsync() such array is not needed:

    IL_0001:  ldarg.0
    IL_0002:  call       instance class [WindowsBase]System.Windows.Threading.Dispatcher [WindowsBase]System.Windows.Threading.DispatcherObject::get_Dispatcher()
    IL_0007:  ldarg.1
    IL_0008:  ldc.i4.0
    IL_0009:  newarr     [mscorlib]System.Object
    IL_000e:  callvirt   instance class [WindowsBase]System.Windows.Threading.DispatcherOperation [WindowsBase]System.Windows.Threading.Dispatcher::BeginInvoke(class [mscorlib]System.Delegate, object[])
    
    
    IL_0014:  ldarg.0
    IL_0015:  call       instance class [WindowsBase]System.Windows.Threading.Dispatcher [WindowsBase]System.Windows.Threading.DispatcherObject::get_Dispatcher()
    IL_001a:  ldarg.1
    IL_001b:  callvirt   instance class [WindowsBase]System.Windows.Threading.DispatcherOperation [WindowsBase]System.Windows.Threading.Dispatcher::InvokeAsync(class [mscorlib]System.Action)
    
    0 讨论(0)
提交回复
热议问题