使用 C# 或 Visual Basic 调用异步 API

通用 Windows 平台 (UWP) 包含许多异步 API,可确保应用在执行可能花费大量时间的任务时仍能保持响应。 本主题将介绍如何从采用 C# 或 Microsoft Visual Basic 的 UWP 使用异步方法。

异步 API 使应用在继续执行之前不会等待大型操作完成。 例如,从 Internet 下载信息的应用可能需要几秒钟时间等待信息到达。 如果使用同步方法检索信息,则会阻止应用,直到该方法返回。 该应用不会响应用户交互,因为它似乎无响应,因此用户可能会感到沮丧。 通过提供异步 API,UWP 可帮助确保在应用执行长时间操作时保持对用户的响应。

UWP 中的大多数异步 API 没有同步的对应项,因此需要确保在 通用 Windows 平台 (UWP) 应用中将异步 API 与 C# 或 Visual Basic 配合使用。 下面介绍如何调用 UWP 的异步 API。

使用异步 API

按照约定,异步方法的名称以“Async”结尾。 通常调用异步 API 来响应用户的操作,例如当用户单击按钮时。 在事件处理程序中调用异步方法是使用异步 API 的最简单方法之一。 此处我们使用 await 运算符作为示例。

假设你有一个应用,其中列出了来自特定位置的博客文章标题。 应用具有一个 按钮,用户单击该按钮 即可获取游戏。 标题显示在 TextBlock。 当用户单击按钮时,应用在等待博客网站中的信息时保持响应非常重要。 为了确保这种响应能力,UWP 提供异步方法 SyndicationClient.RetrieveFeedAsync 来下载源。

以下示例通过调用异步方法 SyndicationClient.RetrieveFeedAsync 并等待结果,从博客获取博客文章列表。

// Put the keyword async on the declaration of the event handler.
private async void Button_Click_1(object sender, RoutedEventArgs e)
{

    Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();

    Uri feedUri
        = new Uri("http://windowsteamblog.com/windows/b/windowsexperience/atom.aspx");

    try
    {
        SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);

        // The rest of this method executes after await RetrieveFeedAsync completes.
        rssOutput.Text = feed.Title.Text + Environment.NewLine;

        foreach (SyndicationItem item in feed.Items)
        {
            rssOutput.Text += item.Title.Text + ", " +
                             item.PublishedDate.ToString() + Environment.NewLine;
        }
    }
    catch (Exception ex)
    {
        // Log Error.
        rssOutput.Text =
            "I'm sorry, but I couldn't load the page," +
            " possibly due to network problems." +
            "Here's the error message I received: "
            + ex.ToString();
    }
}
' Put the keyword Async on the declaration of the event handler.
Private Async Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
    Dim client As New Windows.Web.Syndication.SyndicationClient()
    Dim feedUri As New Uri("http://windowsteamblog.com/windows/b/windowsexperience/atom.aspx")

    Try
        Dim feed As SyndicationFeed = Await client.RetrieveFeedAsync(feedUri)

        ' The rest of this method executes after the await operation completes.
        rssOutput.Text = feed.Title.Text & vbCrLf

        For Each item In feed.Items
            rssOutput.Text += $"{item.Title.Text}, {item.PublishedDate.ToString()}{vbCrLf}"
        Next

    Catch ex As Exception
        ' Log Error.
        rssOutput.Text = "I'm sorry, but I couldn't load the page," &
                         " possibly due to network problems." &
                         "Here's the error message I received: " &
                          ex.ToString()
    End Try

End Sub

本示例有几点重要内容。 首先, SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri) 该行使用 await 运算符和对异步方法 RetrieveFeedAsync 的调用。 可以将 await 运算符视为告知编译器调用异步方法,这会导致编译器执行一些额外的工作,这样就不必这样做。 接下来,事件处理程序的声明包括关键字 异步。 必须在使用 await 运算符的任何方法的方法声明中包括此关键字。

在本主题中,我们不会深入介绍编译器对 await 运算符执行的操作的许多详细信息,但让我们来看看你的应用执行的操作,以便它是异步和响应的。 请考虑使用同步代码时会发生什么情况。 例如,假设有一个称为 SyndicationClient.RetrieveFeed 同步的方法。 (没有这样的方法,但想象有。如果应用包含该行 SyndicationFeed feed = client.RetrieveFeed(feedUri),而不是 SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri)应用的执行将停止,直到返回值 RetrieveFeed 可用为止。 当应用等待方法完成时,它无法响应任何其他事件,例如另一个 Click 事件。 也就是说,你的应用将被阻止,直到 RetrieveFeed 返回。

但是,如果调用 client.RetrieveFeedAsync,该方法将启动检索并立即返回。 将 await 与 RetrieveFeedAsync 配合使用时,应用会暂时退出事件处理程序。 然后,它可以在 RetrieveFeedAsync 异步执行时处理其他事件。 这会使应用能够响应用户。 当 RetrieveFeedAsync 完成并且 SyndicationFeed 可用时,应用实质上会重新输入事件处理程序,在该事件处理程序离开后SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri),并完成该方法的其余部分。

使用 await 运算符的一件好事是,如果使用的是虚构 RetrieveFeed 方法,代码看起来与代码的外观没有太大不同。 在 C# 或 Visual Basic 中编写异步代码的方法没有 await 运算符,但生成的代码往往强调异步执行的机制。 这使得异步代码难以编写、难以理解和难以维护。 通过使用 await 运算符,可以获得异步应用的优势,而无需使代码复杂。

返回异步 API 的类型和结果

如果遵循了 RetrieveFeedAsync 的链接,则可能已注意到 RetrieveFeedAsync返回类型不是 SyndicationFeed。 相反,返回类型为 IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress>. 从原始语法中查看,异步 API 返回一个对象,该对象包含其中的结果。 虽然通常(有时很有用)认为异步方法是可等待的, 但 await 运算符实际上对方法的返回值而不是方法进行操作。 应用 await 运算符时,返回的结果是对方法返回的对象调用 GetResult 的结果。 在此示例中,SyndicationFeed 是 RetrieveFeedAsync.GetResult() 的结果

使用异步方法时,可以检查签名,以查看在等待从方法返回的值后返回的内容。 UWP 中的所有异步 API 返回以下类型之一:

异步方法的结果类型与 TResult 类型参数相同。 没有 TResult 结果的类型。 可以将结果视为 无效。 在 Visual Basic 中, Sub 过程等效于具有 void 返回类型的方法。

此处的表提供了异步方法的示例,并列出了每个方法的返回类型和结果类型。

异步方法 返回类型 结果类型
SyndicationClient.RetrieveFeedAsync IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress> SyndicationFeed
FileOpenPicker.PickSingleFileAsync IAsyncOperation<StorageFile> StorageFile
XmlDocument.SaveToFileAsync IAsyncAction void
InkStrokeContainer.LoadAsync IAsyncActionWithProgress<UInt64> void
DataReader.LoadAsync DataReaderLoadOperation,一个实现 IAsyncOperation< UInt32 的自定义结果类> UInt32

 

在 .NET 中为 UWP 应用定义的异步方法具有返回类型 Task 或 Task< TResult> 返回 Task 的方法类似于返回 IAsyncAction 的 UWP 中的异步方法。 在每个情况下,异步方法的结果为 void。 返回类型 Task TResult 类似于 IAsyncOperation<TResult>>,因为运行任务时异步方法的结果与类型参数的类型相同。TResult< 有关将 .NET 用于 UWP 应用和任务的详细信息,请参阅 .NET for Windows 运行时 应用概述

处理错误

使用 await 运算符从异步方法检索结果时,可以使用 try/catch 块来处理异步方法中发生的错误,就像对同步方法所做的那样。 前面的示例在 try/catch 块中包装 RetrieveFeedAsync 方法和 await 操作,以在引发异常时处理错误。

当异步方法调用其他异步方法时,导致异常的任何异步方法都将传播到外部方法。 这意味着可以将 try/catch 块放在最外部的方法上,以捕获嵌套异步方法的错误。 同样,这类似于捕获同步方法的异常的方式。 但是,不能在 catch 块中使用 await

提示从 visual Studio 2005 Microsoft C# 开始,可以在 catch 块中使用 await

总结和后续步骤

我们在此处显示的调用异步方法的模式是调用事件处理程序中的异步 API 时使用的最简单方法。 在返回 voidVisual Basic 中的 Sub 的重写方法中调用异步方法时,还可以使用此模式。

在 UWP 中遇到异步方法时,请务必记住:

  • 按照约定,异步方法的名称以“Async”结尾。
  • 使用 await 运算符的任何方法都必须使用 异步 关键字标记其声明。
  • 当应用找到 await 运算符时,当异步方法执行时,应用将保持对用户交互的响应。
  • 等待异步方法返回的值将返回包含结果的对象。 在大多数情况下,返回值中包含的结果非常有用,而不是返回值本身。 可以通过查看异步方法的返回类型来查找结果中包含的值的类型。
  • 使用异步 API 和 异步 模式通常是提高应用的响应能力的方法。

本主题中的示例输出如下所示的文本。

Windows Experience Blog
PC Snapshot: Sony VAIO Y, 8/9/2011 10:26:56 AM -07:00
Tech Tuesday Live Twitter #Chat: Too Much Tech #win7tech, 8/8/2011 12:48:26 PM -07:00
Windows 7 themes: what’s new and what’s popular!, 8/4/2011 11:56:28 AM -07:00
PC Snapshot: Toshiba Satellite A665 3D, 8/2/2011 8:59:15 AM -07:00
Time for new school supplies? Find back-to-school deals on Windows 7 PCs and Office 2010, 8/1/2011 2:14:40 PM -07:00
Best PCs for blogging (or working) on the go, 8/1/2011 10:08:14 AM -07:00
Tech Tuesday – Blogging Tips and Tricks–#win7tech, 8/1/2011 9:35:54 AM -07:00
PC Snapshot: Lenovo IdeaPad U460, 7/29/2011 9:23:05 AM -07:00
GIVEAWAY: Survive BlogHer with a Sony VAIO SA and a Samsung Focus, 7/28/2011 7:27:14 AM -07:00
3 Ways to Stay Cool This Summer, 7/26/2011 4:58:23 PM -07:00
Getting RAW support in Photo Gallery & Windows 7 (…and a contest!), 7/26/2011 10:40:51 AM -07:00
Tech Tuesdays Live Twitter Chats: Photography Tips, Tricks and Essentials, 7/25/2011 12:33:06 PM -07:00
3 Tips to Go Green With Your PC, 7/22/2011 9:19:43 AM -07:00
How to: Buy a Green PC, 7/22/2011 9:13:22 AM -07:00
Windows 7 themes: the distinctive artwork of Cheng Ling, 7/20/2011 9:53:07 AM -07:00