2012-11-16 16 views
50

Ho notato in .NET 4.5 che lo WPF Dispatcher aveva ottenuto un nuovo set di metodi per eseguire le cose sul thread del Dispatcher chiamato InvokeAsync. Prima, .NET 4.5 avevamo Invoke e BeginInvoke che gestivano questo in maniera sincrona e asincrona rispettivamente.Qual è la differenza tra InvokeAsync e BeginInvoke per WPF Dispatcher

Oltre alla denominazione e ai sovraccarichi leggermente diversi disponibili, esistono differenze significative tra i metodi BeginInvoke e InvokeAsync?

Oh, e ho già controllato, entrambi possono essere await ndr:

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

risposta

40

Non ci sono differenze come metodo BeginInvoke chiama un LegacyBeginInvokeImpl metodo privato che itslef chiama il metodo privato InvokeAsyncImpl (il metodo usato da InvokeAsync). Quindi è praticamente la stessa cosa. Sembra che sia un semplice refactoring, tuttavia è strano che i metodi BeginInvoke non siano stati contrassegnati come obsoleti.

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; 
} 
+5

Attualmente sto ottenendo eccezioni non gestite che funzionano come previsto utilizzando BeginInvoke (attivando sia DispatcherUnh andledException sul dispatcher e AppDomain.CurrentDomain.UnhandledException), ma le eccezioni non gestite su InvokeAsync vengono silenziosamente ingerite. Continuare l'attività da InvokeAsync con qualcosa per intercettare le eccezioni sembra essere un lavoro valido. – Lamarth

+2

'BeginInvoke' è modellato dopo il [" Modello di programmazione asincrono "] (https://msdn.microsoft.com/en-us/library/ms228963 (v = vs.110) .aspx) in .NET che utilizza' BeginSomething 'e' EndSomething' metodi per operazioni asincrone. Presumibilmente questo è il motivo per cui non è stato designato deprecato o obsoleto. Tranne che la convenzione 'Begin' /' End' è per l'uso di 'IAsyncResult', e' BeginInvoke' no, né esiste alcun 'EndInvoke', quindi era in qualche modo superfluo in primo luogo. – sidbushes

-1

[Edit - entrambi sono nello stesso]

Thereotically

opere BeginInvoke sul thread su cui è stato creato il dispatcher e InvokeAsync funziona con il thread su cui è associato il dispatcher.

Significa che se è necessario elaborare qualcosa basandosi sul thread corrente del dispatcher, si utilizzerà InvokeAsync altrimenti utilizzare BeginInvoke.

MODIFICA: - ma il commento sopra non ha senso poiché non è possibile modificare il thread associato del dispatcher una volta creato.

D'accordo con sopra risposta menzione .. grazie

+0

Potete fornire alcuni riferimenti per favore? –

+0

Sarei anche interrotto, poiché il codice recuperato grazie a ILSpy non mostra differenze tra i due metodi – Sisyphe

+2

Non penso sia vero. MSDN dice "Esegui ... sul thread il Dispatcher è ** associato a **" su circa metà degli overload del metodo 'BeginInvoke' e" Esegui ... sul thread che il Dispatcher era ** creato su ** " sull'altra metà. Sono abbastanza sicuro che significhi semplicemente la stessa cosa. – Clemens

11

C'è una differenza nel metodo di firma:

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

Per BeginInvoke() compilatore crea serie Object[] implicitamente mentre per InvokeAsync() non è necessario tale varietà:

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) 
Problemi correlati