c# - WPF Dispatcher.InvokeAsync() 异步委托(delegate)的奇怪行为

标签 c# wpf async-await dispatcher

如果您有异步方法,如下所示:

    private async Task DoAsync()
    {
        Console.WriteLine(@"(1.1)");
        Thread.Sleep(200);
        Console.WriteLine(@"(1.2)");
        await Task.Delay(1000);
        Console.WriteLine(@"(1.3)");
    }

然后您使用 Dispatcher 异步调用它:

        Console.WriteLine(@"(1)");
        await Application.Current.Dispatcher.InvokeAsync(DoAsync);
        Console.WriteLine(@"(2)");

您将获得的输出将是: (1) (1.1) (1.2) (2) (1.3)

如果您使用 Dispatcher.BeginInvoke() 并且您将等待 Completed 事件,效果将是相同的(这是预期的):

        Console.WriteLine(@"(1)");
        var dispatcherOp = Dispatcher.BeginInvoke(new Func<Task>(DoAsync));
        dispatcherOp.Completed += (s, args) =>
        {               
        Console.WriteLine(@"(2)");
        };

我们在这里看到的是 DoAsync() 方法中的 await 使 Dispatcher 认为操作已结束。

我的问题:这是错误还是功能?您知道描述此行为的任何文档吗?我找不到任何东西。

我不是在寻求解决方法。

最佳答案

这是您代码中的错误,从Application.Current.Dispatcher.InvokeAsync(DoAsync); 返回的对象是 Task<Task> ,你只等待外部任务,而不是等待内部任务完成。这些情况是什么 .Unwrap() 是为了。

    Console.WriteLine(@"(1)");
    await Application.Current.Dispatcher.InvokeAsync(DoAsync).Unwrap();
    Console.WriteLine(@"(2)");

您将获得的输出将是:(1) (1.1) (1.2) (1.3) (2)

Unwrap 所做的是有效地将您的代码转换为

    Console.WriteLine(@"(1)");
    await (await Application.Current.Dispatcher.InvokeAsync(DoAsync));
    Console.WriteLine(@"(2)");

但格式更漂亮。

有关文档,请参阅“How to: Unwrap a nested task

关于c# - WPF Dispatcher.InvokeAsync() 异步委托(delegate)的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48368667/

相关文章:

c# - 替换 <li> 中的控件

c# - 在 C# 中将 Excel 所有列读取为字符串

c# - 我该如何解决这个错误?时间:2019-03-08 标签:c#asplinq

c# - 如何让双击编辑在我的 ListView 中的一行上工作?

c# - 使用 MVVM 绑定(bind) ComboBox SelectedItem

node.js - 错误: Callback was already called in loopback

c# - "Analyzer with Code Fix"项目模板已损坏

c# - 奇怪的 WPF 错误

rust - 如何在 Rust 中以异步方式运行另一个函数?

node.js - 将异步函数返回的 Promise 类型更改为不同类型