Какая разница между InvokeAsync и BeginInvoke для диспетчера WPF
В .NET 4.5 я заметил, что WPF Dispatcher получил новый набор методов для выполнения файлов в потоке Диспетчера, называемом InvokeAsync. Раньше .NET 4.5 у нас Invoke и BeginInvoke которые обрабатывали это синхронно и асинхронно соответственно.
Помимо названий и немного разных перегрузок, существуют ли какие-либо существенные различия между методами BeginInvoke
и InvokeAsync
?
О, и я уже проверил, оба могут быть await
ed:
private async Task RunStuffOnUiThread(Action action)
{
// both of these works fine
await dispatcher.BeginInvoke(action);
await dispatcher.InvokeAsync(action);
}
Ответы
Ответ 1
Нет различий, поскольку метод BeginInvoke
вызывает частный LegacyBeginInvokeImpl
метод, который itslef вызывает частный метод InvokeAsyncImpl
(метод, используемый InvokeAsync
). Так что это в основном то же самое. Кажется, это простой рефакторинг, однако странно, что методы BeginInvoke
не были отмечены как устаревшие.
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;
}
Ответ 2
Существует различие в сигнатуре метода:
BeginInvoke(Delegate, Object[])
InvokeAsync(Action)
Для BeginInvoke()
компилятор создает массив Object[]
неявно, а для InvokeAsync()
такой массив не нужен:
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
[Изменить - оба одинаковы]
Thereotically
BeginInvoke работает над потоком, на котором был создан диспетчер, и InvokeAsync работает с потоком, с которым связан диспетчер.
Это означает, что если вам нужно обработать somthing на основе текущего потока диспетчера, вы будете использовать InvokeAsync else, используя BeginInvoke.
EDIT: - но выше комментарий не имеет смысла, поскольку вы не можете изменить связанный поток диспетчера после его создания.
Согласитесь с выше упоминанием ответ.. спасибо