В чем разница между InvokeAsync и BeginInvoke для диспетчера WPF
Я заметил в .NET 4.5, что диспетчер WPF получил новый набор методов для выполнения материала в потоке диспетчера под названием InvokeAsync. Раньше .NET 4.5 у нас был Invoke и BeginInvoke который обрабатывал это синхронно и асинхронно соответственно.
помимо именования и немного разных доступных перегрузок, существуют ли какие-либо существенные различия между BeginInvoke и InvokeAsync методами?
Ой, а я уже проверил, как можно awaitЭд:
private async Task RunStuffOnUiThread(Action action)
{
// both of these works fine
await dispatcher.BeginInvoke(action);
await dispatcher.InvokeAsync(action);
}
4 ответов:
нет никаких различий, как
BeginInvokeметод вызывает privateLegacyBeginInvokeImplметод, который 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; }
есть разница в сигнатуре метода:
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)
обработка исключений отличается.
вы можете проверить следующее:
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(); }
[Edit-оба одинаковые]
Thereotically
метод BeginInvoke работает на потоке, в котором был создан объект dispatcher и InvokeAsync работы с резьбой, на которой грузоотправитель связан.
Это означает, что если вам нужно обработать что-то на основе текущего потока диспетчера, вы будете использовать InvokeAsync else use BeginInvoke.
EDIT : - но выше комментарий бессмысленно, как вы не можете изменить связанный поток диспетчера, как только он есть создан.
согласен с вышеупомянутым ответом.. спасибо
Comments