2012-11-16 12 views
50

için InvokeAsync ve BeginInvoke arasındaki fark nedir? .NET 4.5'de, WPF Dispatcher'un Dispeçer'ın InvokeAsync adlı Dispatcher'in iş parçacığı üzerinde çalıştırılması için yeni bir yöntem kümesi olduğunu fark ettim. Önceden, .NET 4.5, sırasıyla bu senkronik ve eşzamansız olarak işleyen Invoke ve BeginInvoke vardı.WPF Dispatcher

Adlandırmanın ve biraz farklı aşırı yüklenmelerin yanı sıra, BeginInvoke ve InvokeAsync yöntemleri arasında büyük farklar var mı?

Oh, ve daha önce bakmıştım, hem await ed olabilir:

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

cevap

40

BeginInvoke yöntem itslef özel yöntem InvokeAsyncImpl (InvokeAsync kullandığı yöntemini çağıran özel LegacyBeginInvokeImpl yöntemini çağırır hiçbir fark yoktur). Yani temelde aynı şey. Basit bir refactoring gibi görünüyor, ancak garip BeginInvoke yöntemleri eskimiş olarak işaret değildi.

Beginınvoke:

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

Şu anda, BeginInvoke kullanarak beklenmedik şekilde çalışan işlenmeyen istisnalar alıyorum (her iki DispatcherUnh tetikleniyor) dağıtıcı ve AppDomain.CurrentDomain.UnhandledException üzerinde andledException, ancak InvokeAsync üzerinde işlenmeyen özel durumlar sessizce yutuluyor. InvokeAsync'ten gelen görevi, özel durumları yakalayacak bir şeyle sürdürmek, geçerli bir çalışma gibi görünüyor. – Lamarth

+2

'BeginInvoke', .NET'te' BeginSomething öğesini kullanan ["Eş Zamanlı Programlama Modeli"] 'nden (https://msdn.microsoft.com/en-us/library/ms228963 (v = vs.110) .aspx) sonra biçimlendirilmiştir Eşzamansız işlemler için 've' EndSomething' yöntemleri. Muhtemelen bu yüzden kullanımdan kaldırılmış veya eski değil. “Begin”/“End” sözleşmesinin “IAsyncResult” ve “BeginInvoke” kelimelerini kullanması dışında herhangi bir “EndInvoke” özelliği yoktur, bu yüzden ilk etapta gereksizdir. – sidbushes

-1

[Düzenleme - her ikisi de aynı]

Thereotically

Beginınvoke eserleri dağıtıcı üzerinde oluşturulduğu iş parçacığı üzerinde ve InvokeAsync, dağıtıcının ilişkili olduğu iş parçacığıyla çalışır.

Geçerli bir dağıtıcı iş parçacığına dayalı bir işlem yapmanız gerekiyorsa, InvokeAsync'i başka bir şekilde BeginInvoke kullanacaksınız demektir.

DÜZENLEME: - ancak bir kez oluşturulduktan sonra dağıtıcının ilişkili iş parçacığını değiştiremediğinizden, yorumların anlamsız olduğu anlamına gelir.

yukarıdaki söz cevap Katılıyorum

.. teşekkürler

+0

Bazı referanslar sağlayabilir misiniz lütfen? –

+0

Ben de ILSpy sayesinde alınan kod iki yöntem – Sisyphe

+2

arasında hiçbir fark göstermediği gibi ben de yakalanmış olur. MSDN, "BeginInvoke" yönteminin aşırı yüklenmesinin yaklaşık yarısında "Dispatcher ** ile ** ilişkilendirildiğini" ... çalıştırdığını ve "Dispatcher'ın ** oluşturulduğu iş parçacığı üzerinde ** çalıştırdığını" söyler ... diğer yarısında. Eminim ki aynı şey demek. – Clemens

11

yöntem imzası bir fark vardır: derleyici örtülü InvokeAsync() için böyle dizi gerekli değildir iken diziyi Object[] oluşturur

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

BeginInvoke() için:

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)