非同期の戻り値の型 (Visual Basic)

非同期メソッドには、Task<TResult>Task、および void の 3 とおりの戻り値の型があります。 Visual Basic では、void の戻り値の型は Sub プロシージャとして作成されます。 非同期メソッドの詳細については、「Async および Await を使用した非同期プログラミング (Visual Basic)」を参照してください。

それぞれの戻り値の型は、次のセクションの 1 つで確認でき、トピックの最後で 3 種類のすべてを使用する例を参照できます。

注意

この例を実行するには、Visual Studio 2012 以降と .NET Framework 4.5 以降が、コンピューターにインストールされている必要があります。

Task(T) 型

TResult 型のオペランドを持つ Return ステートメントを含む非同期メソッドには、戻り値の型として Task<TResult> が使用されます。

次の例では、TaskOfT_MethodAsync 非同期メソッドには整数を返す return ステートメントが含まれます。 そのため、メソッド宣言では、戻り値の型を Task(Of Integer) と指定する必要があります。

' TASK(OF T) EXAMPLE
Async Function TaskOfT_MethodAsync() As Task(Of Integer)

    ' The body of an async method is expected to contain an awaited
    ' asynchronous call.
    ' Task.FromResult is a placeholder for actual work that returns a string.
    Dim today As String = Await Task.FromResult(Of String)(DateTime.Now.DayOfWeek.ToString())

    ' The method then can process the result in some way.
    Dim leisureHours As Integer
    If today.First() = "S" Then
        leisureHours = 16
    Else
        leisureHours = 5
    End If

    ' Because the return statement specifies an operand of type Integer, the
    ' method must have a return type of Task(Of Integer).
    Return leisureHours
End Function

TaskOfT_MethodAsync が await 式の中から呼び出されると、await 式は leisureHours から返されるタスクに格納されている整数値 (TaskOfT_MethodAsync の値) を取得します。 await 式の詳細については、「Await 演算子」を参照してください。

次のコードは、TaskOfT_MethodAsync メソッドを呼び出して待機します。 結果は result1 変数に割り当てられます。

' Call and await the Task(Of T)-returning async method in the same statement.
Dim result1 As Integer = Await TaskOfT_MethodAsync()

次のコードに示すように、TaskOfT_MethodAsync の呼び出しと、Await の適用を分離すると、この仕組みをよく理解できます。 メソッドの宣言から予想されるように、直ちに待機しない TaskOfT_MethodAsync メソッドの呼び出しは、Task(Of Integer) を返します。 タスクは、この例の integerTask 変数に割り当てられます。 integerTaskTask<TResult> であるため、Result 型の TResult プロパティが含まれています。 この場合、TResult が整数型を表します。 AwaitintegerTask に適用されると、integerTaskResult プロパティの内容が await 式の評価となります。 この値は result2 変数に割り当てられます。

警告

Result プロパティは Blocking プロパティです。 タスクが終了する前にアクセスしようとすると、現在アクティブなスレッドは、タスクが完了して値が使用可能になるまで、ブロックされます。 多くの場合、プロパティに直接アクセスする代わりに、Await を使用して値にアクセスする必要があります。

' Call and await in separate statements.
Dim integerTask As Task(Of Integer) = TaskOfT_MethodAsync()

' You can do other work that does not rely on resultTask before awaiting.
textBox1.Text &= "Application can continue working while the Task(Of T) runs. . . . " & vbCrLf

Dim result2 As Integer = Await integerTask

次のコードの表示ステートメントは、result1 変数、result2 変数、および Result プロパティの値が同じであることを確認します。 Result プロパティは Blocking プロパティであり、タスクが待機される前にアクセスしないように注意してください。

' Display the values of the result1 variable, the result2 variable, and
' the resultTask.Result property.
textBox1.Text &= vbCrLf & $"Value of result1 variable:   {result1}" & vbCrLf
textBox1.Text &= $"Value of result2 variable:   {result2}" & vbCrLf
textBox1.Text &= $"Value of resultTask.Result:  {integerTask.Result}" & vbCrLf

Task の戻り値の型

return ステートメントを含まない非同期メソッド、またはオペランドを返さない return ステートメントを含む非同期メソッドは、通常は Task 戻り値の型を指定します。 そのようなメソッドは、仮に同期的に実行するように作成された場合、Sub プロシージャとなります。 非同期メソッドに戻り値の型 Task を使用した場合、呼び出し元のメソッドは Await 演算子を使って、呼び出された async のメソッドが終了するまで、呼び出し元の完了を中断します。

次の例では、非同期メソッド Task_MethodAsync には、return ステートメントが含まれていません。 したがって、Task を待機させるメソッドに、戻り値の型 Task_MethodAsync を指定します。 Task 型の定義は、戻り値を格納する Result プロパティを含みません。

' TASK EXAMPLE
Async Function Task_MethodAsync() As Task

    ' The body of an async method is expected to contain an awaited
    ' asynchronous call.
    ' Task.Delay is a placeholder for actual work.
    Await Task.Delay(2000)
    textBox1.Text &= vbCrLf & "Sorry for the delay. . . ." & vbCrLf

    ' This method has no return statement, so its return type is Task.
End Function

Task_MethodAsync は、同期 Sub または void を返すメソッドを呼び出す場合と同様に、await 式でなく、await ステートメントを使って呼び出され、待機されます。 この場合、Await 演算子の適用によって値は生成されません。

次のコードは、Task_MethodAsync メソッドを呼び出して待機します。

' Call and await the Task-returning async method in the same statement.
Await Task_MethodAsync()

前の Task<TResult> の例のように、次のコードに示すとおり、Task_MethodAsync の呼び出しを Await 演算子の適用から分離することができます。 ただし TaskResult プロパティを持たないこと、また await 演算子が Task に適用されるときに値は生成されないことに注意します。

次のコードは Task_MethodAsync の呼び出しを Task_MethodAsync が返すタスクの待機から分離します。

' Call and await in separate statements.
Dim simpleTask As Task = Task_MethodAsync()

' You can do other work that does not rely on simpleTask before awaiting.
textBox1.Text &= vbCrLf & "Application can continue working while the Task runs. . . ." & vbCrLf

Await simpleTask

Void 型の戻り値

Sub プロシージャの主な用途はイベント ハンドラーです。イベント ハンドラーには戻り値の型がありません。他の言語では、この戻り値の型が void と呼ばれます。 void である戻り値は、void を返すメソッドをオーバーライドするためにも使われます。または「ファイア アンド フォーゲット (撃ち放し)」と分類されるアクティビティを実行するメソッドに対して使われます。ただし、void を返す非同期メソッドを待機することはできないため、できる限り Task を返す必要があります。 このようなメソッドの呼び出し元は、呼び出した非同期メソッドが完了するのを待たずに、完了まで継続できる必要があります。また呼び出し元は、非同期メソッドが生成する値または例外とは無関係である必要があります。

void を返す非同期メソッドの呼び出し元は、メソッドがスローする例外をキャッチすることはできません。そのようなハンドルされない例外によって、アプリケーションが失敗する可能性が高くなります。 Task または Task<TResult> を返す非同期メソッドで例外が発生すると、例外は返されたタスクに格納され、タスクが待機するときに再スローされます。 したがって、例外を生成する場合がある非同期メソッドは Task または Task<TResult> の戻り値の型を持つこと、またメソッドの呼び出しが待機することを確認します。

非同期のメソッドで例外をキャッチする方法の詳細については、「Try...Catch...Finally Statement (Try...Catch...Finally ステートメント)」を参照してください。

次のコードは非同期のイベント ハンドラーを定義します。

' SUB EXAMPLE
Async Sub button1_Click(sender As Object, e As RoutedEventArgs) Handles button1.Click

    textBox1.Clear()

    ' Start the process and await its completion. DriverAsync is a
    ' Task-returning async method.
    Await DriverAsync()

    ' Say goodbye.
    textBox1.Text &= vbCrLf & "All done, exiting button-click event handler."
End Sub

コード例全体

次の Windows Presentation Foundation (WPF) プロジェクトには、このトピックのコード例が含まれています。

このプロジェクトを実行するには、次の手順を実行します。

  1. Visual Studio を起動します。

  2. メニュー バーで、 [ファイル][新規作成][プロジェクト] の順にクリックします。

    [新しいプロジェクト] ダイアログ ボックスが表示されます。

  3. [インストール済み][テンプレート] カテゴリ、 [Visual Basic][Windows] の順にクリックします。 プロジェクトの種類の一覧から [WPF アプリケーション] をクリックします。

  4. プロジェクトの名前として「AsyncReturnTypes」と入力し、[OK] をクリックします。

    ソリューション エクスプローラーに新しいプロジェクトが表示されます。

  5. Visual Studio コード エディターで、 [MainWindow.xaml] タブをクリックします。

    タブが表示されない場合は、ソリューション エクスプローラーで MainWindow.xaml のショートカット メニューを開き、 [開く] をクリックします。

  6. MainWindow.xaml の [XAML] ウィンドウで、コードを次のコードに置き換えます。

    <Window x:Class="MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Button x:Name="button1" Content="Start" HorizontalAlignment="Left" Margin="214,28,0,0" VerticalAlignment="Top" Width="75" HorizontalContentAlignment="Center" FontWeight="Bold" FontFamily="Aharoni" Click="button1_Click"/>
            <TextBox x:Name="textBox1" Margin="0,80,0,0" TextWrapping="Wrap" FontFamily="Lucida Console"/>
    
        </Grid>
    </Window>
    

    テキスト ボックスとボタンを含むシンプルなウィンドウが、MainWindow.xaml の [デザイン] ウィンドウに表示されます。

  7. ソリューション エクスプローラーで MainWindow.xaml.vb のショートカット メニューを開き、 [コードの表示] を選択します。

  8. MainWindow.xaml.vb のコードを次のコードに置き換えます。

    Class MainWindow
    
        ' SUB EXAMPLE
        Async Sub button1_Click(sender As Object, e As RoutedEventArgs) Handles button1.Click
    
            textBox1.Clear()
    
            ' Start the process and await its completion. DriverAsync is a
            ' Task-returning async method.
            Await DriverAsync()
    
            ' Say goodbye.
            textBox1.Text &= vbCrLf & "All done, exiting button-click event handler."
        End Sub
    
        Async Function DriverAsync() As Task
    
            ' Task(Of T)
            ' Call and await the Task(Of T)-returning async method in the same statement.
            Dim result1 As Integer = Await TaskOfT_MethodAsync()
    
            ' Call and await in separate statements.
            Dim integerTask As Task(Of Integer) = TaskOfT_MethodAsync()
    
            ' You can do other work that does not rely on resultTask before awaiting.
            textBox1.Text &= "Application can continue working while the Task(Of T) runs. . . . " & vbCrLf
    
            Dim result2 As Integer = Await integerTask
    
            ' Display the values of the result1 variable, the result2 variable, and
            ' the resultTask.Result property.
            textBox1.Text &= vbCrLf & $"Value of result1 variable:   {result1}" & vbCrLf
            textBox1.Text &= $"Value of result2 variable:   {result2}" & vbCrLf
            textBox1.Text &= $"Value of resultTask.Result:  {integerTask.Result}" & vbCrLf
    
            ' Task
            ' Call and await the Task-returning async method in the same statement.
            Await Task_MethodAsync()
    
            ' Call and await in separate statements.
            Dim simpleTask As Task = Task_MethodAsync()
    
            ' You can do other work that does not rely on simpleTask before awaiting.
            textBox1.Text &= vbCrLf & "Application can continue working while the Task runs. . . ." & vbCrLf
    
            Await simpleTask
        End Function
    
        ' TASK(OF T) EXAMPLE
        Async Function TaskOfT_MethodAsync() As Task(Of Integer)
    
            ' The body of an async method is expected to contain an awaited
            ' asynchronous call.
            ' Task.FromResult is a placeholder for actual work that returns a string.
            Dim today As String = Await Task.FromResult(Of String)(DateTime.Now.DayOfWeek.ToString())
    
            ' The method then can process the result in some way.
            Dim leisureHours As Integer
            If today.First() = "S" Then
                leisureHours = 16
            Else
                leisureHours = 5
            End If
    
            ' Because the return statement specifies an operand of type Integer, the
            ' method must have a return type of Task(Of Integer).
            Return leisureHours
        End Function
    
        ' TASK EXAMPLE
        Async Function Task_MethodAsync() As Task
    
            ' The body of an async method is expected to contain an awaited
            ' asynchronous call.
            ' Task.Delay is a placeholder for actual work.
            Await Task.Delay(2000)
            textBox1.Text &= vbCrLf & "Sorry for the delay. . . ." & vbCrLf
    
            ' This method has no return statement, so its return type is Task.
        End Function
    
    End Class
    
  9. F5 キーを押してプログラムを実行し、 [Start] を複数回クリックします。

    次の出力が表示されます。

    Application can continue working while the Task<T> runs. . . .
    
    Value of result1 variable:   5
    Value of result2 variable:   5
    Value of integerTask.Result: 5
    
    Sorry for the delay. . . .
    
    Application can continue working while the Task runs. . . .
    
    Sorry for the delay. . . .
    
    All done, exiting button-click event handler.
    

関連項目