从基于事件的异步移动到基于任务的异步
本文关键字:异步 于任务 任务 移动 于事件 事件 | 更新日期: 2023-09-27 18:34:52
我正在使用WCF服务在WPF应用程序中加载一些数据,直到最近,我还是通过Visual Studio为我自动生成的基于事件的异步方法这样做的:
//Old way
private void LoadFoos(int barId)
{
serviceClient.SelectFoosByBarIdCompleted += (s, e) =>
{
Foos = e.Result.OrderBy(f => f.Description).ToList();
});
serviceClient.SelectFoosByBarIdAsync();
}
无论出于何种原因,我们转向使用任务,我有一个关于做同样事情的最佳方式的问题:
//New way
private async void LoadFoos(int barId)
{
private TaskScheduler uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
serviceClient.SelectFoosByBarIdAsync(barId).ContinueWith(t =>
{
Foos = t.Result.OrderBy(f => f.Description).ToList();
}, uiTaskScheduler);
}
我认为这更丑陋,因为我必须手动设置上下文,这样我就不会在错误的线程上更新内容(Foos
是一个数据绑定属性(。另外,我想我能够做到这一点:
//New way #2, doesn't sort ;(
private async void LoadFoos(int barId)
{
private TaskScheduler uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var selectFoosTask = serviceClient.SelectFoosByBarIdAsync(barId);
Foos = selectFoosTask;
}
但是我不能根据Description
订购.
整个任务概念对我来说是相当新的,所以也许我错过了一些东西。有没有比我上面列出的更简洁的方法?
你只需要使用等待,而不是延续:
private async Task LoadFoos(int barId)
{
var temp = await serviceClient.SelectFoosByBarIdAsync(barId);
Foos = temp.OrderBy(f => f.Description).ToList();
}
请注意,使用异步 void,甚至只是Task
返回方法可能并不理想。 最好将其重写为(*假设 Foos 是一个List<string>
(:
private async Task<List<string>> LoadFoosAsync(int barId)
{
var temp = await serviceClient.SelectFoosByBarIdAsync(barId);
return temp.OrderBy(f => f.Description).ToList();
}
然后,当您调用它时,请使用:
Foos = await LoadFoosAsync(id);
至于将基于事件的异步方法转换为基于任务的方法(顺便说一下,任务要优越得多:((查看这些博客文章
http://msdn.microsoft.com/en-us/magazine/ff959203.aspxhttp://blogs.msdn.com/b/pfxteam/archive/2009/06/19/9791857.aspx
在封送回 ui 线程之前,您仍然可以执行所有处理。您还可以创建自己的 ContinueWith 帮助程序方法,该方法将任务放在正确的任务计划程序上。(如果您无法使用 await,这是最简单的选项(
另请注意,wsdl 工具的较新版本(我认为是 2012 年及更高版本(实际上为服务生成了基于任务的异步方法。
由于该方法async
只是await
任务,而不是手动添加延续:
private async Task LoadFoos(int barId)
{
Foos = (await serviceClient.SelectFoosByBarIdAsync(barId))
.OrderBy(f => f.Description).ToList();
}
另请注意,应尽可能避免使用async void
方法,因为这样您将无法知道异步操作何时结束,也无法访问引发的任何异常。 而是让该方法返回一个Task
。 更好的方法是让该方法返回一个Task<T>
其中T
是它返回的数据,而不是让该方法设置其他字段。