次の方法で共有


C# または Visual Basic での非同期 API の呼び出し

ユニバーサル Windows プラットフォーム (UWP) には、時間がかかる可能性がある操作を実行しているときでも、アプリの応答性を保つために、さまざまな非同期 API が用意されています。 このトピックでは、C# または Microsoft Visual Basic で UWP の非同期メソッドを使う方法について説明します。

非同期 API では、実行を続行する前に、大規模な操作が完了するまでアプリが待機しないようにします。 たとえば、インターネットから情報をダウンロードするアプリでは、情報が到着するまで数秒待つ場合があります。 同期メソッドを使用して情報を取得する場合、メソッドが戻るまでアプリはブロックされます。 アプリはユーザーの操作に応答せず、応答していないように見えるため、ユーザーが不満を感じる可能性があります。 非同期 API を提供することで、UWP は、アプリが長い操作を実行しているときにユーザーに対する応答性を維持するのに役立ちます。

UWP のほとんどの非同期 API には同期 API がないため、ユニバーサル Windows プラットフォーム (UWP) アプリで C# または Visual Basic で非同期 API を使用する方法を理解する必要があります。 ここでは、UWP の非同期 API を呼び出す方法を示します。

非同期 API の使用

慣例により、非同期メソッドには "Async" で終わる名前が付いています。 通常、ユーザーがボタンをクリックしたときなど、ユーザーのアクションに応答して非同期 API を呼び出します。 イベント ハンドラーで非同期メソッドを呼び出すことは、非同期 API を使用する最も簡単な方法の 1 つです。 ここでは、例として await 演算子を使用します。

特定の場所からのブログ投稿のタイトルを一覧表示するアプリがあるとします。 アプリには、ユーザーがクリックしてタイトルを取得する Button があります。 タイトルは、 TextBlock に表示されます。 ユーザーがボタンをクリックすると、ブログの Web サイトからの情報を待機している間もアプリの応答性を維持することが重要です。 この応答性を確保するために、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)行では、非同期メソッド RetrieveFeedAsync の呼び出しで await 演算子を使用します。 await演算子は、非同期メソッドを呼び出していることをコンパイラに伝えていると考えることができます。これにより、コンパイラは余分な作業を行うので、必要はありません。 次に、イベント ハンドラーの宣言にキーワード async が含まれます。 このキーワードは、 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メソッドを使用した場合のコードの外観とコードの外観が大きく異ならないことです。 await演算子を使用せずに C# または Visual Basic で非同期コードを記述する方法がありますが、結果のコードでは非同期実行の仕組みが強調される傾向があります。 これにより、非同期コードの記述が困難になり、理解が困難になり、保守が困難になります。 await演算子を使用すると、コードを複雑にすることなく、非同期アプリの利点を得ることができます。

非同期 API の型と結果を返す

RetrieveFeedAsyncへのリンクに従った場合、RetrieveFeedAsyncの戻り値の型がSyndicationFeedではないことに気付いた可能性があります。 代わりに、戻り値の型は IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress>。 生の構文から見ると、非同期 API は、その中の結果を含むオブジェクトを返します。 非同期メソッドを待機可能と考えるのは一般的であり、場合によっては便利ですが、 await 演算子は実際にはメソッドではなくメソッドの戻り値に対して動作します。 await演算子を適用すると、戻ってくるのは、メソッドによって返されるオブジェクトに対して GetResult を呼び出した結果です。 この例では、 SyndicationFeedRetrieveFeedAsync.GetResult()の結果です。

非同期メソッドを使用する場合は、シグネチャを調べて、メソッドから返された値を待機した後に返される内容を確認できます。 UWP 内のすべての非同期 API は、次のいずれかの型を返します。

非同期メソッドの結果の型は、 TResult 型パラメーターと同じです。 TResultを持たない型には結果がありません。 結果は void と考えることができます。 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 DataReaderLoadOperationIAsyncOperation<UInt32 を実装するカスタム結果クラス> UInt32

 

UWP アプリの .NET で定義されている非同期メソッドには 戻り値の型 Task または Task<TResult> があります。 Task を返すメソッドは、IAsyncAction を返す UWP の非同期メソッドに似ています。 いずれの場合も、非同期メソッドの結果は void です。 タスク タスク<TResult> の戻り値の型は、 IAsyncOperation<TResult> タスクの実行時の非同期メソッドの結果が TResult 型パラメーターと同じであるという点で似ています。 UWP アプリタスクに .NET を使用する方法の詳細については、「Windows ランタイム アプリの.NET の概要を参照してください。

エラーを処理する

await演算子を使用して非同期メソッドから結果を取得する場合は、同期メソッドの場合と同様に、try/catch ブロックを使用して非同期メソッドで発生するエラーを処理できます。 前の例では、 RetrieveFeedAsync メソッドと await 操作を try/catch ブロックでラップして、例外がスローされたときにエラーを処理します。

非同期メソッドが他の非同期メソッドを呼び出すと、例外が発生するすべての非同期メソッドが外側のメソッドに伝達されます。 つまり、外側のメソッドに try/catch ブロックを配置して、入れ子になった非同期メソッドのエラーをキャッチできます。 繰り返しますが、これは同期メソッドの例外をキャッチする方法と似ています。 ただし、catch ブロックで await を使用することはできません。

ヒント: Microsoft Visual Studio 2005 の C# から、catch ブロックで await を使うことができます。

まとめと次のステップ

ここで示す非同期メソッドを呼び出すパターンは、イベント ハンドラーで非同期 API を呼び出すときに使用する最も簡単なパターンです。 このパターンは、Visual Basic で void または Sub を返すオーバーライドされたメソッドで非同期メソッドを呼び出すときにも使用できます。

UWP で非同期メソッドが発生する場合は、次の点に注意することが重要です。

  • 慣例により、非同期メソッドには "Async" で終わる名前が付いています。
  • await 演算子を使用するメソッドの宣言は、async キーワードでマークされている必要があります。
  • アプリが await 演算子を見つけた場合、非同期メソッドの実行中、アプリはユーザーの操作に対する応答性を維持します。
  • 非同期メソッドによって返される値を待機すると、結果を含むオブジェクトが返されます。 ほとんどの場合、戻り値自体ではなく、戻り値に含まれる結果が役立ちます。 非同期メソッドの戻り値の型を調べることで、結果内に含まれる値の型を確認できます。
  • 非同期 API と async パターンを使用することは、多くの場合、アプリの応答性を向上させる方法です。

このトピックの例では、次のようなテキストを出力します。

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