85

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 and BeginInvoke which handled this syncronously and asynchronously respectively.

Besides the naming and the slightly different overloads available, are there any major differences between the BeginInvoke and the InvokeAsync methods?

Oh, and I already checked, both can be awaited:

private async Task RunStuffOnUiThread(Action action)
{
    // both of these works fine
    await dispatcher.BeginInvoke(action);
    await dispatcher.InvokeAsync(action);
}

4 Answers 4

70

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();
}
4
  • 16
    This should be marked as the correct answer. The fact that BeginInvoke brings down the app on an unhandled exception vs. InvokeAsync flowing the exception back through the returned awaitable is a HUGE difference.
    – jam40jeff
    Aug 1, 2018 at 14:01
  • 1
    @jam40jeff Good point. For those migrating from BeginInvoke to InvokeAsync: imagine a huge legacy application with loads of calls to BeginInvoke. If that is refactored to use InvokeAsync, then an unhandled exception will bubble up from the point of the exception, bringing down the calling thread. On the other hand, BeginInvoke would pass that exception into the main application handler, which is caught and wouldn't bring the application down. Either way, they are not drop-in replacements for each other, and when switching from one to another, test the differences in behavior.
    – Contango
    Feb 26, 2019 at 12:55
  • You state that exception handling is different and give a code example. But you never explicitly state how the exception handling is different. The quality of your answer would improve if you add that.
    – JHBonarius
    Jul 21, 2020 at 8:06
  • @JHBonarius See the comment in the first exception handler.
    – Wouter
    Jul 21, 2020 at 21:57
53

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;
}
4
  • 10
    Currently I'm getting unhandled exceptions working as expected using BeginInvoke (triggering both DispatcherUnhandledException on the dispatcher and AppDomain.CurrentDomain.UnhandledException), but unhandled exceptions on InvokeAsync are being silently swallowed. Continuing the task from InvokeAsync with something to trap exceptions seems to be a valid work around.
    – Lamarth
    Jun 18, 2014 at 9:06
  • 4
    BeginInvoke is patterned after the "Asynchronous Programming Model" in .NET that uses BeginSomething and EndSomething methods for asynchronous operations. Presumably this is why it wasn't designated deprecated or obsolete. Except that the Begin/End convention is for using IAsyncResult, and BeginInvoke doesn't, nor is there any EndInvoke, so it was kind of superfluous in the first place.
    – sidbushes
    Sep 19, 2016 at 16:14
  • 4
    The DispatcherOpartion returned from the constructor has a memberfield useAsyncSematics which is set based on the constructor used. This causes a difference in the exception handling when using async and await. See my answer.
    – Wouter
    Mar 28, 2018 at 7:04
  • This answer is just wrong. The exception handling is different in the two cases. See @Wouter's answer.
    – Hugh W
    Nov 8, 2023 at 20:06
17

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)
3

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.