注:本文由BeyondVincent(破船)原创首发
转载请注明出处:BeyondVincent(破船)@DevDiv.com
更多内容请查看下面的帖子
[DevDiv原创]Windows 8 开发Step by Step
注1:本文译自Programming Windows, 6th Edition Charpter 7 Calling Your Own Async Methods
假设你用类似下面的这个方法进行隔离存贮中文件保存的逻辑:
async void SaveFile(string text)
{
FileSavePicker picker = new FileSavePicker();
picker.DefaultFileExtension = ".txt";
picker.FileTypeChoices.Add("Text", new List<string> { ".txt" });
StorageFile storageFile = await picker.PickSaveFileAsync();
if (storageFile == null)
return;
await FileIO.WriteTextAsync(storageFile, txtbox.Text);
}
这个方法必须标记为async,因为它有await关键字。然后你可以在OnSaveAsAppBarButtonClick函数中这样调用:
void OnSaveAsAppBarButtonClick(object sender, RoutedEventArgs args)
{
SaveFile(txtbox.Text);
}
OnSaveAsAppBarButtonClick调用SaveFile发生什么呢:SaveFile开始执行,直到第一个await后的PickSaveFileAsync被调用,在这里,SaveFile函数终止并将控制权返回给OnSaveAsAppBarButtonClick函数。当PickSaveFileAsync结果准备好了,SaveFile剩余的代码继续被执行。
在这种特殊情况下,是正确的。然而,如果如果你想要OnSaveAsAppBarButtonClick方法等待SaveFile的执行,必须包含await关键字,并用async标识OnSaveAsAppBarButtonClick方法:
async void OnSaveAsAppBarButtonClick(object sender, RoutedEventArgs args)
{
await SaveFile(txtbox.Text);
}
但是,当你这样做的话,SaveFile必须要改变一下。它不能再返回void。你可以有许多种方法修改SaveFile,但是可能最简单方法就是将返回类型修改为Task:
async Task SaveFile(string text)
{
...
}
在这里,你可能想将方法的名字改为SaveFileAsync,标识这是一个异步方法,可以被等待。即使在SaveFileAsync方法中没有写明运行在别的线程里,但是调用SaveFileAsync的异步方法会在另外的线程中处理。
下面的OnOpenAppBarButtonClick与ReadFileAsync方法又有点不同。你可能希望ReadFileAsync方法返回文件中的文本内容,所以返回类型不是Task,而是Task<string>:
async Task<string> ReadFileAsync()
{
FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".txt");
StorageFile storageFile = await picker.PickSingleFileAsync();
if (storageFile == null)
return null;
return await FileIO.ReadTextAsync(storageFile);
}
然后可以像如下调用ReadFileAsync:
async void OnOpenAppBarButtonClick(object sender, RoutedEventArgs args)
{
string text = await ReadFileAsync();
if (text != null)
txtbox.Text = text;
}
认识到这些所有的代码都在用户界面线程执行很重要。你不用担心UI对象的访问。FileIO的两个方法是在别的线程中运行的,由于ReadFileAsync方法调用了其它的异步方法,所以它也是异步的。方法中的其它代码则在UI线程运行。
如果你自己写的代码需要很长的处理时间,而你不希望在UI线程中处理,替代传统的技术(创建并执行线程)是考虑使用与Windows Runtime一样的基于任务的方法。你可以将要执行的代码以函数的方式传递给静态方法Task.Run。如下示例:
Task<double> BigJobAsync(int arg1, int arg2)
{
return Task.Run<double>(() =>
{ double val = 0;
// ... lengthy code
return val;
});
}
在匿名方法中的所执行的内容都是在另外一个线程中进行的。这也会引起一个问题:它不能访问UI对象。然后,你可以按照下面的代码来访问这个方法:
double value = await BigJobAsync(22, 33);
如果,BigJobAsync中的匿名方法包含了await操作,那么需要将匿名方法标记为async:
Task<double> BigJobAsync(int arg1, int arg2)
{
return Task.Run<double>(async () =>
{ double val = 0;
// ... lengthy code
return val;
});
}
在后面的章节中,我会详细介绍异步处理。