C# WPF Dispatcher 的 InvokeAsync 和 BeginInvoke 有什么区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13412670/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 08:28:37  来源:igfitidea点击:

What's the difference between InvokeAsync and BeginInvoke for WPF Dispatcher

c#wpf.net-4.5async-await

提问by Isak Savo

I noticed in .NET 4.5 that the WPF Dispatcherhad gotten a new set of methods to execute stuff on the Dispatcher's thread called InvokeAsync. Before, .NET 4.5 we had Invokeand BeginInvokewhich handled this syncronously and asynchronously respectively.

我注意到在 .NET 4.5 中,WPF Dispatcher获得了一组新的方法来在 Dispatcher 的线程上执行称为InvokeAsync 的东西。在 .NET 4.5 之前,我们有InvokeBeginInvoke,它们分别以同步和异步方式处理。

Besides the naming and the slightly different overloads available, are there any major differences between the BeginInvokeand the InvokeAsyncmethods?

除了命名和可用的重载略有不同之外,BeginInvokeInvokeAsync方法之间有什么主要区别吗?

Oh, and I already checked, both can be awaited:

哦,我已经检查过了,两者都可以await编辑:

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

采纳答案by Sisyphe

There are no differences as the BeginInvokemethod calls a private LegacyBeginInvokeImplmethod which itslef calls the private method InvokeAsyncImpl(the method used by InvokeAsync). So it's basically the same thing. It seems like it's a simple refactoring, however it's strange the BeginInvokemethods weren't flagged as obsolete.

没有区别,因为该BeginInvoke方法调用了一个私有LegacyBeginInvokeImpl方法,而其本身调用了私有方法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;
}

回答by user2341923

There is a difference in method signature:

方法签名有区别:

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

For BeginInvoke()compiler creates array Object[]implicitly while for InvokeAsync()such array is not needed:

对于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)

回答by Wouter

The exception handling is different.

异常处理是不同的。

You may want to check the following:

您可能需要检查以下内容:

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();
}

回答by Chris S.

Well, one difference I've noticed is that InvokeAsync has a generic overload that returns a DispatcherOperation as a return value and accepts a Func as its delegate input parameter. Thus, you can retrieve the result of the operation via InvokeAsync in a type-safe way analogous to how you can await the result of a Task.

嗯,我注意到的一个区别是 InvokeAsync 有一个通用重载,它返回一个 DispatcherOperation 作为返回值,并接受一个 Func 作为其委托输入参数。因此,您可以通过 InvokeAsync 以类似于等待任务结果的方式安全的方式检索操作的结果。