WPF Dispatcher的InvokeAsync和BeginInvoke之间有什么区别

Isa*_*avo 61 c# wpf async-await .net-4.5

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

除了命名和稍微不同的重载外,这些BeginInvokeInvokeAsync方法之间是否有任何重大差异?

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

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

Sis*_*phe 45

没有区别,因为该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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 目前我正在使用BeginInvoke(在调度程序和AppDomain.CurrentDomain.UnhandledException上触发DispatcherUnhandledException)按预期运行未处理的异常,但是正在静默吞下InvokeAsync上未处理的异常.从InvokeAsync继续执行任务以捕获异常似乎是一个有效的解决方法. (6认同)
  • 在.NET中使用`BeginSomething`的["异步编程模型"](https://msdn.microsoft.com/en-us/library/ms228963(v = vs.110).aspx)之后,`BeginInvoke`被模式化了.和用于异步操作的`EndSomething`方法.据推测,这就是为什么它没有被指定为已弃用或过时.除了`Begin` /`End`约定是使用`IAsyncResult`,而`BeginInvoke`没有,也没有'EndInvoke`,所以它首先是多余的. (2认同)
  • 从构造函数返回的DispatcherOpartion有一个成员字段useAsyncSematics,它是根据使用的构造函数设置的.当使用async和await时,这会导致异常处理的差异.看我的回答. (2认同)

Wou*_*ter 22

异常处理是不同的.

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

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该标记为正确的答案.事实上,"BeginInvoke"在未处理的异常上关闭应用程序,而"InvokeAsync"将异常流回返回的等待状态是一个巨大的差异. (6认同)

use*_*923 13

方法签名有所不同:

BeginInvoke(Delegate, Object[])
InvokeAsync(Action)
Run Code Online (Sandbox Code Playgroud)

对于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)
Run Code Online (Sandbox Code Playgroud)