非同期プログラムにおける制御フロー (C# および Visual Basic)
Async と Await のキーワードを使用して非同期のプログラムをより簡単に作成および保持できます。ただし、結果は、プログラムがどのように動作するかを理解してわからない場合があります。このトピックでは、コントロールを 1 回のメソッド間で移動するたびに移動すると、どの情報を表示する単純な非同期のプログラムによる制御フローを格納します。
[!メモ]
Async と Await のキーワードは、Visual Studio 2012 で導入されました。そのバージョンの新しい機能に関する詳細については、Visual Studio 2012 の新機能を参照してください。
一般に、Async (Visual Basic) または async (C#) 修飾子の非同期コードを含むメソッドをマークします。async 修飾子でマークされたメソッドでは、呼び出される非同期処理を待機するメソッドがどこに変化するかを指定するために 待機します (Visual Basic) または 待機します (、C) の演算子を使用できます。詳細については、「Async および Await を使用した非同期プログラミング (C# および Visual Basic)」を参照してください。
次の例では、指定した Web サイトの内容を文字列としてダウンロードし、文字列の長さを表示するには、非同期のメソッドを使用します。この例は、次の 2 とおりの方法があります。
startButton_Click、AccessTheWebAsync を呼び出し、結果を表示します。
AccessTheWebAsync、文字列としてサイトのコンテンツをダウンロードし、文字列の長さを返します。AccessTheWebAsync は、コンテンツをダウンロードするには HttpClient の非同期メソッド、GetStringAsync(String)を使用します。
番号付き表示行はプログラム全体を使用しながら、重要なポイントについて理解し、プログラムの実行発生するマークされている各ポイントで説明するためです。表示行は "1 "、"6" ラベルによって"。ラベルは、プログラムのこれらのコード行に到達する順序を表します。
次のコードでは、プログラムの概要を次に示します。
Class MainWindow
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click
' ONE
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
' FOUR
Dim contentLength As Integer = Await getLengthTask
' SIX
ResultsTextBox.Text &=
String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength)
End Sub
Async Function AccessTheWebAsync() As Task(Of Integer)
' TWO
Dim client As HttpClient = New HttpClient()
Dim getStringTask As Task(Of String) =
client.GetStringAsync("https://msdn.microsoft.com")
' THREE
Dim urlContents As String = Await getStringTask
' FIVE
Return urlContents.Length
End Function
End Class
public partial class MainWindow : Window
{
// . . .
private async void startButton_Click(object sender, RoutedEventArgs e)
{
// ONE
Task<int> getLengthTask = AccessTheWebAsync();
// FOUR
int contentLength = await getLengthTask;
// SIX
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
async Task<int> AccessTheWebAsync()
{
// TWO
HttpClient client = new HttpClient();
Task<string> getStringTask =
client.GetStringAsync("https://msdn.microsoft.com");
// THREE
string urlContents = await getStringTask;
// FIVE
return urlContents.Length;
}
}
ラベルの位置、それぞれに 6 "、"1 "" "、プログラムの現在の状態に関する情報を表示します。次の出力が生成されます。
ONE: Entering startButton_Click.
Calling AccessTheWebAsync.
TWO: Entering AccessTheWebAsync.
Calling HttpClient.GetStringAsync.
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
Length of the downloaded string: 33946.
プログラムを設定します。
このトピックを MSDN から使用するか、独自に作成できますコードをダウンロードできます。
[!メモ]
例を実行するには、Visual Studio 2012 が必要です Visual Studio 2012 では、またはがコンピューターにインストールされている .NET Framework 4.5 を表します。
プログラムをダウンロードします。
このトピックのアプリケーションをから 単一の例: 単一のプログラムの制御フローダウンロードできます。次の手順が開き、プログラムの実行。
ダウンロードされたファイルを解凍し、Visual Studio 2012を起動します。
メニュー バーで [ファイル]、[開く]、[プロジェクト/ソリューション] の順に選択します。
ファイルを解凍されたサンプル コードを保持するフォルダーを開き、ソリューション (.sln) ファイルを、次に、プロジェクトをビルドして実行するように選択して F5 キーを移動します。
プログラム独自のビルド
Windows Presentation Foundation (WPF) の次のプロジェクトは、このトピックのコード例を示します。
プロジェクトを実行するには、次の手順を実行します:
Visual Studio を起動します。
メニュー バーで [ファイル]、[新規]、[プロジェクト] の順にクリックします。
[新しいプロジェクト] ダイアログ ボックスが表示されます。
[インストールされたテンプレート] のペインで、[Visual Basic] か [Visual C#] を選択し、プロジェクトの種類の一覧 [WPF アプリケーション] を選択します。
AsyncTracer にプロジェクトの名前として" "と入力し、[OK] のボタンをクリックします。
ソリューション エクスプローラーに新しいプロジェクトが表示されます。
Visual Studio では、エディターを選択します [MainWindow.xaml] のタブを参照してください。
タブが表示されない場合は、[ソリューション エクスプローラー] で MainWindow.xaml のショートカット メニューを開き、[コードの表示] を選択します。
MainWindow.xaml の [XAML] ビューで、次のコードに置き換えます。
<Window xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MainWindow" Title="Control Flow Trace" Height="350" Width="525"> <Grid> <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="221,10,0,0" VerticalAlignment="Top" Width="75"/> <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="510" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" d:LayoutOverrides="HorizontalMargin"/> </Grid> </Window>
<Window xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="AsyncTracer.MainWindow" Title="Control Flow Trace" Height="350" Width="592"> <Grid> <Button x:Name="startButton" Content="Start
" HorizontalAlignment="Left" Margin="250,10,0,0" VerticalAlignment="Top" Width="75" Height="24" Click="startButton_Click" d:LayoutOverrides="GridBox"/> <TextBox x:Name="resultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="576" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" Grid.ColumnSpan="3"/> </Grid> </Window>
テキスト ボックスとボタンを含む簡単なウィンドウは、MainWindow.xaml の [デザイン] ビューに表示されます。
System.Net.Httpの参照を追加します。
[ソリューション エクスプローラー] では、MainWindow.xaml.cs のショートカット メニューを開き、[コードの表示] を選択します。
MainWindow.xaml.vb または MainWindow.xaml.cs で、次のコードに置き換えます。
' Add an Imports statement and a reference for System.Net.Http. Imports System.Net.Http Class MainWindow Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click ' The display lines in the example lead you through the control shifts. ResultsTextBox.Text &= "ONE: Entering StartButton_Click." & vbCrLf & " Calling AccessTheWebAsync." & vbCrLf Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync() ResultsTextBox.Text &= vbCrLf & "FOUR: Back in StartButton_Click." & vbCrLf & " Task getLengthTask is started." & vbCrLf & " About to await getLengthTask -- no caller to return to." & vbCrLf Dim contentLength As Integer = Await getLengthTask ResultsTextBox.Text &= vbCrLf & "SIX: Back in StartButton_Click." & vbCrLf & " Task getLengthTask is finished." & vbCrLf & " Result from AccessTheWebAsync is stored in contentLength." & vbCrLf & " About to display contentLength and exit." & vbCrLf ResultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength) End Sub Async Function AccessTheWebAsync() As Task(Of Integer) ResultsTextBox.Text &= vbCrLf & "TWO: Entering AccessTheWebAsync." ' Declare an HttpClient object. Dim client As HttpClient = New HttpClient() ResultsTextBox.Text &= vbCrLf & " Calling HttpClient.GetStringAsync." & vbCrLf ' GetStringAsync returns a Task(Of String). Dim getStringTask As Task(Of String) = client.GetStringAsync("https://msdn.microsoft.com") ResultsTextBox.Text &= vbCrLf & "THREE: Back in AccessTheWebAsync." & vbCrLf & " Task getStringTask is started." ' AccessTheWebAsync can continue to work until getStringTask is awaited. ResultsTextBox.Text &= vbCrLf & " About to await getStringTask & return a Task(Of Integer) to StartButton_Click." & vbCrLf ' Retrieve the website contents when task is complete. Dim urlContents As String = Await getStringTask ResultsTextBox.Text &= vbCrLf & "FIVE: Back in AccessTheWebAsync." & vbCrLf & " Task getStringTask is complete." & vbCrLf & " Processing the return statement." & vbCrLf & " Exiting from AccessTheWebAsync." & vbCrLf Return urlContents.Length End Function End Class
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; // Add a using directive and a reference for System.Net.Http; using System.Net.Http; namespace AsyncTracer { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void startButton_Click(object sender, RoutedEventArgs e) { // The display lines in the example lead you through the control shifts. resultsTextBox.Text += "ONE: Entering startButton_Click.\r\n" + " Calling AccessTheWebAsync.\r\n"; Task<int> getLengthTask = AccessTheWebAsync(); resultsTextBox.Text += "\r\nFOUR: Back in startButton_Click.\r\n" + " Task getLengthTask is started.\r\n" + " About to await getLengthTask -- no caller to return to.\r\n"; int contentLength = await getLengthTask; resultsTextBox.Text += "\r\nSIX: Back in startButton_Click.\r\n" + " Task getLengthTask is finished.\r\n" + " Result from AccessTheWebAsync is stored in contentLength.\r\n" + " About to display contentLength and exit.\r\n"; resultsTextBox.Text += String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength); } async Task<int> AccessTheWebAsync() { resultsTextBox.Text += "\r\nTWO: Entering AccessTheWebAsync."; // Declare an HttpClient object. HttpClient client = new HttpClient(); resultsTextBox.Text += "\r\n Calling HttpClient.GetStringAsync.\r\n"; // GetStringAsync returns a Task<string>. Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com"); resultsTextBox.Text += "\r\nTHREE: Back in AccessTheWebAsync.\r\n" + " Task getStringTask is started."; // AccessTheWebAsync can continue to work until getStringTask is awaited. resultsTextBox.Text += "\r\n About to await getStringTask and return a Task<int> to startButton_Click.\r\n"; // Retrieve the website contents when task is complete. string urlContents = await getStringTask; resultsTextBox.Text += "\r\nFIVE: Back in AccessTheWebAsync." + "\r\n Task getStringTask is complete." + "\r\n Processing the return statement." + "\r\n Exiting from AccessTheWebAsync.\r\n"; return urlContents.Length; } } }
プログラムを実行するには、F5 キーを選択し、を [開始] のボタンをクリックします。
次の出力が表示されます。
ONE: Entering startButton_Click. Calling AccessTheWebAsync. TWO: Entering AccessTheWebAsync. Calling HttpClient.GetStringAsync. THREE: Back in AccessTheWebAsync. Task getStringTask is started. About to await getStringTask & return a Task<int> to startButton_Click. FOUR: Back in startButton_Click. Task getLengthTask is started. About to await getLengthTask -- no caller to return to. FIVE: Back in AccessTheWebAsync. Task getStringTask is complete. Processing the return statement. Exiting from AccessTheWebAsync. SIX: Back in startButton_Click. Task getLengthTask is finished. Result from AccessTheWebAsync is stored in contentLength. About to display contentLength and exit. Length of the downloaded string: 33946.
プログラムを書き込む。
手順 1 および 2
最初の 2 種類の行が表示 startButton_Click が AccessTheWebAsyncを呼び出すと、AccessTheWebAsync の呼び出しを HttpClient の非同期メソッド GetStringAsync(String)トレースとして渡します。次の図は、メソッドからメソッドへの呼び出しについて説明します。
両方の AccessTheWebAsync と client.GetStringAsync の戻り値の型は Task<TResult>です。AccessTheWebAsyncでは、TResult は整数です。GetStringAsyncでは、TResult は文字列です。非同期メソッドの戻り値の型に関する詳細については、非同期の戻り値の型 (C# および Visual Basic)を参照してください。
タスクを返す非同期のメソッドは、コントロールが呼び出し元に戻します移動するタスクのインスタンスを返します。コントロールは、非同期のメソッドから呼び出し元に Await または await の演算子が、呼び出されたメソッドで実行されるか、呼び出されたメソッドが終了するといずれかを返します。 "6 "の" トレースを通じて "3 "" をこのプロセスの一部と表示行ラベル。
手順 3
AccessTheWebAsyncで、ターゲット Web ページのコンテンツをダウンロードするには、非同期メソッド GetStringAsync(String) が呼び出されます。コントロールは client.GetStringAsync から AccessTheWebAsync に client.GetStringAsync がを返す場合にを返します。
client.GetStringAsync のメソッドは AccessTheWebAsyncの getStringTask の変数に再配置文字列のタスクを返します。プログラム例の次の行は client.GetStringAsync および割り当てに呼び出しを示します。
Dim getStringTask As Task(Of String) = client.GetStringAsync("https://msdn.microsoft.com")
Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com");
client.GetStringAsync によって約束としてタスクに関する実際の文字列が最終的に生成する考えることができます。AccessTheWebAsync にする必要 client.GetStringAsyncから約束された文字列に依存しない作業がある場合は、その処理は client.GetStringAsync を待機している間、続行できます。例では"、3 "というラベル出力次の行は独立した作業を行う機会を表します。
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
次のステートメントは getStringTask が待たれる場合 AccessTheWebAsync の進行状況を中断します。
Dim urlContents As String = Await getStringTask
string urlContents = await getStringTask;
次の図は client.GetStringAsync への割り当て getStringTask への変換と getStringTask の作成から予想演算子のアプリケーションにコントロールのフローを示しています。
要求の式は client.GetStringAsync が返されるまで AccessTheWebAsync を中断します。一方、コントロールは AccessTheWebAsync、startButton_Clickの呼び出し元に返します。
[!メモ]
通常、非同期メソッドへの呼び出しをすぐに待機します。たとえば、次の 1 つが getStringTaskを作成し、待機前のコードを置換する場合:
Visual Basic: Dim urlContents As String = Await client.GetStringAsync("https://msdn.microsoft.com")
C#: string urlContents = await client.GetStringAsync("https://msdn.microsoft.com");
このトピックでは、プログラムによる制御フローを示す出力行に対応するために、予期演算子が後に適用されます。
手順 4
AccessTheWebAsync の戻り値の型の宣言は、C の Visual Basic と Task<int> の Task(Of Integer) です。したがって、AccessTheWebAsync が中断されるときに、startButton_Clickに整数のタスクを返します。返されたタスクが getStringTaskではないことを理解する必要があります。返されたタスクは、中断されたメソッドでされることがあるか AccessTheWebAsync表す整数の新しいタスクです。タスクはタスクが完了すると整数を生成 AccessTheWebAsync から約束です。
次のステートメントは getLengthTask の変数にこのタスクを再配置。
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Task<int> getLengthTask = AccessTheWebAsync();
AccessTheWebAsyncのように、startButton_Click は、非同期タスク (getLengthTask) の結果に依存しない作業をタスクが待たれるまで続行できます。次の出力は、その行作業を表します。
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
startButton_Click の進行状況は、getLengthTask が待たれると中断されます。次の代入ステートメントは、AccessTheWebAsync が完了するまで startButton_Click を中断します。
Dim contentLength As Integer = Await getLengthTask
int contentLength = await getLengthTask;
次の図では、矢印に AccessTheWebAsync で getLengthTask が予期待たれるまでの式から startButton_Click の通常の処理に続く値の割り当て getLengthTaskするへのコントロールのフローを示しています。
手順 5
完了したことに client.GetStringAsync が通知を送信すると、AccessTheWebAsync で処理して中断から解放され、予想過去のステートメントを継続できます。出力次の行の処理は再開を表します。
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
return ステートメント、urlContents.Lengthのオペランドは AccessTheWebAsync が返すタスクに格納されます。startButton_Clickの getLengthTask から評価する予定の式のを取得します。
次の図は client.GetStringAsync (および getStringTask) の後に制御の移動が完了したことを示します。
AccessTheWebAsync は、完了時に実行され、完了するまで待機するコントロールは startButton_Clickにを返します。
手順 6
完了したことに AccessTheWebAsync が通知を送信すると、処理は必要 startButton_Asyncの過去のステートメントを継続できます。実際、プログラムは何も行うことはありません。
出力次の行は startButton_Asyncの処理の再開を表します:
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
要求の式は getLengthTask から AccessTheWebAsyncの return ステートメントのオペランドである整数値を取得します。contentLength に変数を評価する次のステートメントの割り当て。
Dim contentLength As Integer = Await getLengthTask
int contentLength = await getLengthTask;
次の図は AccessTheWebAsync から startButton_Clickに制御が戻ることを示しています。
参照
処理手順
チュートリアル: Async と Await を使用した Web へのアクセス (C# および Visual Basic)
概念
Async および Await を使用した非同期プログラミング (C# および Visual Basic)
非同期の戻り値の型 (C# および Visual Basic)