web-dev-qa-db-de.com

Was ist der Unterschied zwischen InvokeAsync und BeginInvoke für WPF Dispatcher?

In .NET 4.5 ist mir aufgefallen, dass der WPF Dispatcher eine neue Gruppe von Methoden zum Ausführen von Dingen im Dispatcher-Thread namens InvokeAsync erhalten hat. Vor .NET 4.5 hatten wir Invoke und BeginInvoke , die dies synchron und asynchron handhabten.

Gibt es neben der Benennung und den geringfügig unterschiedlichen Überladungen größere Unterschiede zwischen den Methoden BeginInvoke und InvokeAsync

Oh, und ich habe bereits geprüft, beide können awaited sein:

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

Es gibt keine Unterschiede, da die BeginInvoke-Methode eine private LegacyBeginInvokeImpl-Methode aufruft, die itslef die private Methode InvokeAsyncImpl (die von InvokeAsync verwendete Methode) aufruft. Also ist es im Grunde dasselbe. Es scheint, als wäre es ein einfaches Refactoring, jedoch ist es seltsam, dass die BeginInvoke-Methoden nicht als veraltet markiert wurden.

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;
}
40
Sisyphe

Die Ausnahmebehandlung ist unterschiedlich.

Möglicherweise möchten Sie Folgendes überprüfen:

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();
}
11
Wouter

Es gibt einen Unterschied in der Methodensignatur:

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

Für BeginInvoke() erstellt der Compiler das Array Object[] implizit, während für InvokeAsync() ein solches Array nicht benötigt wird:

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)
11
user2341923

Nun, ein Unterschied, den ich bemerkt habe, ist, dass InvokeAsync eine generische Überladung aufweist, die eine DispatcherOperation als Rückgabewert zurückgibt und eine Func als ihren Eingabeparameter für Delegaten akzeptiert. So können Sie das Ergebnis der Operation über InvokeAsync auf eine typsichere Weise abrufen, ähnlich wie Sie das Ergebnis einer Task abwarten können.

1
Chris S.