非同步傳回類型(Visual Basic)Async Return Types (Visual Basic)

非同步方法有三種可能的傳回類型:Task<TResult>Task 和 void。Async methods have three possible return types: Task<TResult>, Task, and void. 在 Visual Basic 中,void 傳回型別會撰寫為 Sub 程序。In Visual Basic, the void return type is written as a Sub procedure. 如需非同步方法的詳細資訊,請參閱使用 async 和 Await 進行非同步程式設計(Visual Basic)For more information about async methods, see Asynchronous Programming with Async and Await (Visual Basic).

每個傳回型別在下列其中一節探討,您可以在主題結尾處找到使用全部三種類型的完整範例。Each return type is examined in one of the following sections, and you can find a full example that uses all three types at the end of the topic.

注意

若要執行範例,您必須在電腦上安裝 Visual Studio 2012 或更新版本以及 .NET Framework 4.5 或更新版本。To run the example, you must have Visual Studio 2012 or newer and the .NET Framework 4.5 or newer installed on your computer.

Task(T) 傳回型別Task(T) Return Type

Task<TResult> 傳回型別用於非同步方法,其中包含return語句,其中運算元的型別為 TResultThe Task<TResult> return type is used for an async method that contains a Return statement in which the operand has type TResult.

在下列範例中,TaskOfT_MethodAsync 非同步方法包含一個傳回整數的 return 陳述式。In the following example, the TaskOfT_MethodAsync async method contains a return statement that returns an integer. 因此,方法宣告必須指定 Task(Of Integer) 傳回型別。Therefore, the method declaration must specify a return type of 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

從 await 運算式內呼叫 TaskOfT_MethodAsync 時,await 運算式會擷取儲存在 TaskOfT_MethodAsync 所傳回之工作中的整數值 (leisureHours 的值)。When TaskOfT_MethodAsync is called from within an await expression, the await expression retrieves the integer value (the value of leisureHours) that's stored in the task that's returned by TaskOfT_MethodAsync. 如需 await 運算式的詳細資訊,請參閱Await 運算子For more information about await expressions, see Await Operator.

下列程式碼會呼叫並等候方法 TaskOfT_MethodAsyncThe following code calls and awaits method TaskOfT_MethodAsync. 結果會指派給 result1 變數。The result is assigned to the result1 variable.

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

您可以藉由區隔對 TaskOfT_MethodAsync 的呼叫與 Await 的應用,深入了解這種運作方式,如下列程式碼所示。You can better understand how this happens by separating the call to TaskOfT_MethodAsync from the application of Await, as the following code shows. 呼叫不會立即等候的 TaskOfT_MethodAsync 方法,會傳回 Task(Of Integer),如您所預期的方法宣告。A call to method TaskOfT_MethodAsync that isn't immediately awaited returns a Task(Of Integer), as you would expect from the declaration of the method. 在範例中,工作會指派給 integerTask 變數。The task is assigned to the integerTask variable in the example. 因為 integerTaskTask<TResult>,所以它包含 TResult 類型的 Result 屬性。Because integerTask is a Task<TResult>, it contains a Result property of type TResult. 在此情況下,TResult 代表整數類型。In this case, TResult represents an integer type. Await 套用至 integerTask 時,await 運算式評估為 integerTaskResult 屬性的內容。When Await is applied to integerTask, the await expression evaluates to the contents of the Result property of integerTask. 值會指派給 result2 變數。The value is assigned to the result2 variable.

警告

Result 屬性是封鎖的屬性。The Result property is a blocking property. 如果您嘗試在其工作完成之前先存取它,目前使用中的執行緒會封鎖,直到工作完成並且有可用的值為止。If you try to access it before its task is finished, the thread that's currently active is blocked until the task completes and the value is available. 在大部分情況下,您應該使用 Await 來存取值,而不是直接存取屬性。In most cases, you should access the value by using Await instead of accessing the property directly.

' 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 陳述式會驗證 result1 變數、result2 變數和 Result 屬性的值相同。The display statements in the following code verify that the values of the result1 variable, the result2 variable, and the Result property are the same. 請記住,Result 屬性是封鎖屬性,在等候其工作之前不應該存取它。Remember that the Result property is a blocking property and shouldn't be accessed before its task has been awaited.

' 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 Type

不包含 return 陳述式的非同步方法,或包含不會傳回運算元的 return 陳述式的非同步方法,通常具有傳回型別 TaskAsync methods that don't contain a return statement or that contain a return statement that doesn't return an operand usually have a return type of Task. 這類方法是撰寫成同步執行的Sub程式。Such methods would be Sub procedures if they were written to run synchronously. 如果您針對非同步方法使用 Task 傳回型別,則除非被呼叫的非同步方法完成,否則呼叫的方法可以使用 Await 運算子暫止呼叫端完成。If you use a Task return type for an async method, a calling method can use an Await operator to suspend the caller's completion until the called async method has finished.

在下列範例中,非同步方法 Task_MethodAsync 不包含 return 陳述式。In the following example, async method Task_MethodAsync doesn't contain a return statement. 因此,您為方法指定 Task 傳回型別,如此可等候 Task_MethodAsyncTherefore, you specify a return type of Task for the method, which enables Task_MethodAsync to be awaited. Task 類型的定義不包含用來儲存傳回值的 Result 屬性。The definition of the Task type doesn't include a Result property to store a return value.

' 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

使用 await 陳述式呼叫並等候 Task_MethodAsync,而不是使用 await 運算式,類似於同步 Sub 或傳回 void 方法的呼叫陳述式。Task_MethodAsync is called and awaited by using an await statement instead of an await expression, similar to the calling statement for a synchronous Sub or void-returning method. 在此情況下,Await 運算子的應用不會產生值。The application of an Await operator in this case doesn't produce a value.

下列程式碼會呼叫並等候方法 Task_MethodAsyncThe following code calls and awaits method Task_MethodAsync.

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

如同先前的 Task<TResult> 範例,您可以從 Await 運算子的應用程式中分隔 Task_MethodAsync 的呼叫,如下列程式碼所示。As in the previous Task<TResult> example, you can separate the call to Task_MethodAsync from the application of an Await operator, as the following code shows. 不過,請記住,Task 沒有 Result 屬性,且將 await 運算子套用至 Task 時不會產生任何值。However, remember that a Task doesn't have a Result property, and that no value is produced when an await operator is applied to a Task.

下列程式碼會區隔 Task_MethodAsync 的呼叫與等候 Task_MethodAsync 傳回的工作。The following code separates calling Task_MethodAsync from awaiting the task that Task_MethodAsync returns.

' 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 傳回型別Void Return Type

Sub 程式的主要用途是在事件處理常式中,沒有傳回型別(稱為其他語言的 void 傳回型別)。The primary use of Sub procedures is in event handlers, where there is no return type (referred to as a void return type in other languages). void 傳回也可用來覆寫傳回 void 的方法,或執行可分類為「射後不理」(fire and forget) 之活動的方法。A void return also can be used to override void-returning methods or for methods that perform activities that can be categorized as "fire and forget." 不過,您應該盡可能傳回 Task,因為無法等候傳回 void 的非同步方法。However, you should return a Task wherever possible, because a void-returning async method can't be awaited. 這種方法的任何呼叫端必須要能夠繼續完成而不需等待呼叫的非同步方法完成,且呼叫端必須與非同步方法產生的任何值或例外狀況無關。Any caller of such a method must be able to continue to completion without waiting for the called async method to finish, and the caller must be independent of any values or exceptions that the async method generates.

傳回 void 的非同步方法的呼叫端無法攔截方法擲回的例外狀況,這類未處理的例外狀況有可能造成應用程式失敗。The caller of a void-returning async method can't catch exceptions that are thrown from the method, and such unhandled exceptions are likely to cause your application to fail. 如果例外狀況發生在會傳回 TaskTask<TResult> 的非同步方法,則例外狀況會儲存在傳回的工作中,並在等候工作時再次擲回。If an exception occurs in an async method that returns a Task or Task<TResult>, the exception is stored in the returned task, and rethrown when the task is awaited. 因此,請確定任何可能會產生例外狀況的非同步方法具有傳回型別 TaskTask<TResult>,且會等候對方法的呼叫。Therefore, make sure that any async method that can produce an exception has a return type of Task or Task<TResult> and that calls to the method are awaited.

如需如何在非同步方法中攔截例外狀況的詳細資訊,請參閱 Try...Catch...Finally 陳述式For more information about how to catch exceptions in async methods, see Try...Catch...Finally Statement.

下列程式碼會定義非同步事件處理常式。The following code defines an async event handler.

' 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

完整範例Complete Example

下列 Windows Presentation Foundation (WPF) 專案包含本土的程式碼範例。The following Windows Presentation Foundation (WPF) project contains the code examples from this topic.

若要執行專案,請執行下列步驟:To run the project, perform the following steps:

  1. 啟動 Visual Studio。Start Visual Studio.

  2. 在功能表列上,選擇 [ 檔案]、[ 新增]、[ 專案]。On the menu bar, choose File, New, Project.

    [ 新增專案 ] 對話方塊隨即開啟。The New Project dialog box opens.

  3. 在 [已安裝範本] 分類中,選擇 [ Visual Basic],然後選擇 [ Windows]。In the Installed, Templates category, choose Visual Basic, and then choose Windows. 在專案類型清單中,選擇 [WPF 應用程式]。Choose WPF Application from the list of project types.

  4. 輸入 AsyncReturnTypes 作為專案的名稱,然後選擇 [確定] 按鈕。Enter AsyncReturnTypes as the name of the project, and then choose the OK button.

    新的專案隨即出現在方案總管中。The new project appears in Solution Explorer.

  5. 在 Visual Studio 程式碼編輯器中,選擇 [ MainWindow.xaml ] 索引標籤。In the Visual Studio Code Editor, choose the MainWindow.xaml tab.

    如果未顯示索引標籤,請在方案總管中開啟 MainWindow.xaml 的捷徑功能表,然後選擇 [開啟]。If the tab is not visible, open the shortcut menu for MainWindow.xaml in Solution Explorer, and then choose Open.

  6. 在 MainWindow.xaml 的 [XAML] 視窗中,將程式碼取代為下列程式碼。In the XAML window of MainWindow.xaml, replace the code with the following code.

    <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 的 [設計] 視窗中。A simple window that contains a text box and a button appears in the Design window of MainWindow.xaml.

  7. 方案總管中,開啟 mainwindow.xaml 的快捷方式功能表,然後選擇 [ View Code]。In Solution Explorer, open the shortcut menu for MainWindow.xaml.vb, and then choose View Code.

  8. 以下列程式碼取代 MainWindow.xaml.vb 中的程式碼。Replace the code in MainWindow.xaml.vb with the following code.

    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 鍵以執行程式,然後選擇 [ 開始 ] 按鈕。Choose the F5 key to run the program, and then choose the Start button.

    應該會出現下列輸出:The following output should appear:

    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.
    

請參閱See also