web-dev-qa-db-fra.com

Quelle est la différence entre InvokeAsync et BeginInvoke pour WPF Dispatcher

J'ai remarqué dans .NET 4.5 que le WPF Dispatcher avait reçu un nouvel ensemble de méthodes pour exécuter des tâches sur le thread du Dispatcher appelé InvokeAsync . Auparavant, .NET 4.5, nous avions Invoke et BeginInvoke qui gérait cela de manière syncroneuse et asynchrone, respectivement.

Outre la dénomination et les surcharges légèrement différentes disponibles, existe-t-il des différences majeures entre les méthodes BeginInvoke et InvokeAsync

Oh, et j'ai déjà vérifié, les deux peuvent être awaited:

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

Il n'y a pas de différence puisque la méthode BeginInvoke appelle une méthode privée LegacyBeginInvokeImpl, comme itslef appelle la méthode privée InvokeAsyncImpl (la méthode utilisée par InvokeAsync). Donc, c'est fondamentalement la même chose. Il semble que ce soit une simple refactorisation, mais il est étrange que les méthodes BeginInvoke n'aient pas été marquées comme obsolètes.

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

La gestion des exceptions est différente.

Vous voudrez peut-être vérifier les éléments suivants:

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

Il y a une différence dans la signature de la méthode:

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

Pour BeginInvoke() le compilateur crée le tableau Object[] implicitement, alors que pour InvokeAsync() un tel tableau n’est pas nécessaire

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

Eh bien, une différence que j'ai remarquée est qu'InvokeAsync a une surcharge générique qui renvoie un DispatcherOperation en tant que valeur de retour et accepte un Func comme paramètre d'entrée délégué. Ainsi, vous pouvez récupérer le résultat de l'opération via InvokeAsync de manière sécurisée au type, de la même manière que vous pouvez attendre le résultat d'une tâche.

1
Chris S.