Windows Store apps开发[36]Await和Async

来源:互联网 发布:淘宝货到付款店 编辑:程序博客网 时间:2024/06/03 18:49

注:本文由BeyondVincent(破船)原创首发

        转载请注明出处:BeyondVincent(破船)@DevDiv.com



更多内容请查看下面的帖子


[DevDiv原创]Windows 8 开发Step by Step


    注1:本文译自Programming Windows, 6th Edition Charpter 7 Await and Async

    注2:本文内容是关于Await和Async的一个简介,关于详细内容,我会在后续文章中进行介绍

    注3:通过本文的阅读,你可以知道如何在Windows 8中进行简单的异步调用,以及一些注意事项。


    C# 5.0的关键字await允许我们对异步的操作就如同正常方法的调用一样。SimplePad2程序除了在应用程序栏中的按钮处理打开和保存外,跟SimplePad1一样。下面是Save按钮的Click事件处理代码:

工程:SimplePad2 | 文件:MainPage.xaml.cs(节选)

async void OnSaveAsAppBarButtonClick(object sender, RoutedEventArgs args){    FileSavePicker picker = new FileSavePicker();    picker.DefaultFileExtension = ".txt";    picker.FileTypeChoices.Add("Text", new List<string> { ".txt" });    // Asynchronous call!    StorageFile storageFile = await picker.PickSaveFileAsync();    if (storageFile == null)        return;    // Asynchronous call!    await FileIO.WriteTextAsync(storageFile, txtbox.Text);}
    注意两个await前面的注释。PickSaveFileAsync实际上是返回一个IAsyncOperation,一般你需要给它设置一个完成处理的函数,然后在这个完成处理回调中调用GetResults以获取StorageFile对象。await操作看似绕过了所有复杂的东西,而是直接简单的返回 StorageFile。这究竟是怎么回事呢?

    这看起来很神奇,但是许多杂乱的实现细节已经隐藏起来了。C#编译器生成回调(callback),并且调用GetResults。但是await操作同样将该方法转入一个状态机。(But what the await operator also does is turn the method in which it’s used into a state machine.)OnSaveAsAppBarButtonClick方法开始执行很正常,直到PickSaveFileAsync被调用以及await第一次出现。

    虽然名为await,但是await并不等待操作完成。相反,Click处理函数在这里退出了。控制权回到Windows。其它的代码,可以在程序用户界面线程继续执行,同时也可以对进行文件选取(file-picker)。当文件选取器消失了,即用户对文件选取的结果已经出来了,那么UI线程就准备执行一些代码——继续执行Click处理函数:赋值storageFile变量,然后继续往下执行,直到下一个await操作。就像这样,可以一直往下执行许多await操作(如果有),直到函数完成。

    在Click处理函数中的最后一行代码调用了静态方法FileIO.WriteTextAsync。严格来将,这里的await操作符可以不需要,因为在这里并不需要这个方法的执行结果。File.WriteTextAsync方法不返回任何内容,并且在Click处理函数中,并没有其它代码依赖于此的。因此在这种ing狂下,await操作符可以移除,程序代码如下:

FileIO.WriteTextAsync(storageFile, txtbox.Text);

    你会收到一条来自编译器的警告消息,但是这没问题。await操作符只在下面两种情况比较关键:你需要从异步方法中获得一个返回值,再者就是在程序逻辑上继续执行之前,异步方法必须完成则需要使用await操作符。
    下面是Open按钮的Click事件处理函数,使用了静态方法FileIO.ReadTextAsync:

工程:SimplePad2 | 文件:MainPage.xaml.cs(节选)

async void OnOpenAppBarButtonClick(object sender, RoutedEventArgs args){    FileOpenPicker picker = new FileOpenPicker();    picker.FileTypeFilter.Add(".txt");    // Asynchronous call!    StorageFile storageFile = await picker.PickSingleFileAsync();    if (storageFile == null)        return;    // Asynchronous call!    txtbox.Text = await FileIO.ReadTextAsync(storageFile);}


    在await出现之前,C#中异步操作的调用总是有悖于语言的必要组织结构。await操作符带来了必要组织结构,并将异步调用转换为一系列普通方法的调用。而且在Click处理函数中的所有事情都是在UI线程中进行的,因此必用考虑用户界面对象的访问。虽然await的使用,更加简单,但是你要记住的是如果一个函数中出现了await,那么实际上在后端是将该函数分片处理的。

    这里有一些await的使用条款。await不能出现在异常处理的catch或finally语句中。而它可以出现在try语句中,这也是捕获异步函数发生错误的方法。同关键字,样还提供了取消操作,以及一些异步函数的进度通知。这些具体细节我将在后面的异步操作章节中介绍。

    如果函数中出现了await操作符,那么该函数必须用async标识,但是async并不做其它更多的事情。在早期的C#版本中,await并不是一个关键字,所以程序员可以将这个单词(await)用作变量名或属性名,或者其它任何内容。C#5.0中添加了await关键字将改变这一现状,不过使用async标识来限制函数中的await。async不会改变函数的签名——上面的方法任然是Click的处理方法。但是async(以及await)不能被用在入口点,如Main或者类的构造函数中

    如果你需要在初始化一个FrameworkElement子类时调用异步方法,那么请在Loaded事件处理函数中进行,并将处理函数标记为async:

public MainPage(){    this.InitializeComponent();    ...    Loaded += OnLoaded;}async void OnLoaded(object sender, RoutedEventArgs arg){    ...}

或者,如果你喜欢的话,可以按照下面的代码,将Loaded处理函数定义为一个异步函数:

public MainPage(){    this.InitializeComponent();    ...    Loaded += async (sender, args) =>    {        ...    };}

看到参数列表前的async了吗?

    


原创粉丝点击