WPF Dispatcher.InvokeAsync() 异步委托的奇怪行为
WPF Dispatcher.InvokeAsync() strange behavior with async delegate
如果您有异步方法,如下所示:
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”
如果您有异步方法,如下所示:
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”