WPF Dispatcher.InvokeAsync()与异步委托的奇怪行为

Mac*_*ski 2 c# wpf dispatcher async-await

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

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

并使用Dispatcher异步调用它:

        Console.WriteLine(@"(1)");
        await Application.Current.Dispatcher.InvokeAsync(DoAsync);
        Console.WriteLine(@"(2)");
Run Code Online (Sandbox Code Playgroud)

你得到的输出将是:(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)");
        };
Run Code Online (Sandbox Code Playgroud)

我们在这里看到的是DoAsync()方法中的await使得Dispatcher相信操作已经结束.

我的问题:这是一个错误还是一个功能?你知道任何描述这种行为的文件吗?我找不到任何东西.

我不是要求解决方法.

Sco*_*ain 7

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

    Console.WriteLine(@"(1)");
    await Application.Current.Dispatcher.InvokeAsync(DoAsync).Unwrap();
    Console.WriteLine(@"(2)");
Run Code Online (Sandbox Code Playgroud)

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

Unwrap正在做的是有效地将代码转换为

    Console.WriteLine(@"(1)");
    await (await Application.Current.Dispatcher.InvokeAsync(DoAsync));
    Console.WriteLine(@"(2)");
Run Code Online (Sandbox Code Playgroud)

但具有更好看的格式.

有关文档,请参阅" 如何:展开嵌套任务 "

  • @oleh:Dispatcher.InvokeAsync返回一个DispatcherOperation,而不是一个Task,但是,它是可等待的,因此await关键字起作用。获取任务并进行解包:Dispatcher.InvokeAsync(DoAsync).Task.Unwrap() (2认同)