Share via


非同步方法的傳回型別 (C# and Visual Basic)

Async 方法有三個可能的傳回型別: Task<TResult>Task和虛值 (Void)。 在 Visual Basic 中, void 傳回型別是寫入為 子函數 程序。 如需這些方法的詳細資訊,請參閱使用 Async 和 Await 設計非同步程式 (C# 和 Visual Basic)

每個傳回型別在下列其中一個區段中檢查,因此,您可以找到使用三種類型的完整範例在本主題的結尾。

注意事項注意事項

若要執行此範例,您必須將 Visual Studio 2012 中, Windows 桌面上的 Visual Studio Express 2012 for或者在您的電腦上安裝 .NET Framework 4.5。

本主題包含下列章節。

  • 工作 (T) 傳回型別
  • 工作 (T) 傳回型別
  • void 傳回型別
  • 完整範例
  • 相關主題

工作 (T) 傳回型別

Task<TResult> 傳回型別用於async方法,其包含 傳回 的非同步方法使用 (Visual Basic) 或 傳回 (C#) 陳述式運算元的型別 TResult。

在下列範例中, TaskOfT_MethodAsync 非同步方法包含傳回整數的一個 return 陳述式。 因此,在 Visual Basic 中為方法宣告必須指定 Task(Of Integer) 或 Task<int> 的傳回型別 (在 C# 中)

' 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<T> EXAMPLE
async Task<int> TaskOfT_MethodAsync()
{
    // The body of the method is expected to contain an awaited asynchronous
    // call.
    // Task.FromResult is a placeholder for actual work that returns a string.
    var today = await Task.FromResult<string>(DateTime.Now.DayOfWeek.ToString());

    // The method then can process the result in some way.
    int leisureHours;
    if (today.First() == 'S')
        leisureHours = 16;
    else
        leisureHours = 5;

    // Because the return statement specifies an operand of type int, the
    // method must have a return type of Task<int>.
    return leisureHours;
}

當等候呼叫運算式內部呼叫 TaskOfT_MethodAsync 時,等候運算式擷取由 TaskOfT_MethodAsync傳回的整數值 (leisureHours的值)。 如需物件運算式的詳細資訊,請參閱Await 運算子 (Visual Basic)await (C# 參考)

下列程式碼會呼叫並等待方法 TaskOfT_MethodAsync。 此值已被指派給 result1 變數。

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

您可以進一步了解這是如何發生的,藉由分隔這個對 TaskOfT_MethodAsync 的呼叫從 Await 或 await的應用程式,如下列程式碼所示。 對不是立即等候的傳回每 Task(Of Integer) 或 Task<int>的 TaskOfT_MethodAsync 方法的呼叫,如同預期方法的宣告。 工作指派至範例中的 integerTask 變數。 由於 integerTask 是 Task<TResult>,其包含型別 TResult一 Result 屬性。 在這種情況下, TResult 表示整數類資料型別。 當 Await 或 await 套用至 integerTask時,等候運算式為 integerTaskResult 屬性的內容。 此值已被指派給 result2 變數。

警告

Result 屬性是一個封鎖的屬性。如果您嘗試存取它,在它的工作完成之前,使用中執行緒遭到封鎖,直到工作完成和值為可用狀態為止。在許多情況下,您應該存取值使用 Await 或 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 &= String.Format("Application can continue working while the Task(Of T) runs. . . . " & vbCrLf)

Dim result2 As Integer = Await integerTask
// Call and await in separate statements.
Task<int> integerTask = TaskOfT_MethodAsync();

// You can do other work that does not rely on integerTask before awaiting.
textBox1.Text += String.Format("Application can continue working while the Task<T> runs. . . . \r\n");

int result2 = await integerTask;

在下列程式碼顯示的陳述式來驗證 result1 變數、 result2 變數和 Result 屬性的值相同。 記得 Result 屬性是一個封鎖的屬性,在它的工作等候之前不應該被存取。

' Display the values of the result1 variable, the result2 variable, and
' the resultTask.Result property.
textBox1.Text &= String.Format(vbCrLf & "Value of result1 variable:   {0}" & vbCrLf, result1)
textBox1.Text &= String.Format("Value of result2 variable:   {0}" & vbCrLf, result2)
textBox1.Text &= String.Format("Value of resultTask.Result:  {0}" & vbCrLf, integerTask.Result)
// Display the values of the result1 variable, the result2 variable, and
// the integerTask.Result property.
textBox1.Text += String.Format("\r\nValue of result1 variable:   {0}\r\n", result1);
textBox1.Text += String.Format("Value of result2 variable:   {0}\r\n", result2);
textBox1.Text += String.Format("Value of integerTask.Result: {0}\r\n", integerTask.Result);

工作 (T) 傳回型別

不包含傳回陳述式或包含傳回陳述式不會傳回運算元的Async方法通常具有 Task傳回型別。 這個方法會傳回空白的方法 (在 Visual Basic 中子函數 程序),如果撰寫同步執行。 如果您提供非同步方法都使用 Task 傳回型別,則呼叫方法可以使用運算子等候逾時呼叫端的完成,直到呼叫非同步方法完成。

在下列範例中,非同步方法 Task_MethodAsync 不包含傳回陳述式。 因此,您會指定方法 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 &= String.Format(vbCrLf & "Sorry for the delay. . . ." & vbCrLf)

    ' This method has no return statement, so its return type is Task. 
End Function
// TASK EXAMPLE
async Task Task_MethodAsync()
{
    // 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);
    // Task.Delay delays the following line by two seconds.
    textBox1.Text += String.Format("\r\nSorry for the delay. . . .\r\n");

    // This method has no return statement, so its return type is Task.  
}

Task_MethodAsync 被呼叫並等待,藉由使用等待陳述式 (而不是等待運算式),類似同步 Sub 或傳回虛值的方法中的呼叫陳述式。 等候運算子的應用程式在這種情況下並不會產生值。

下列程式碼會呼叫並等待方法 Task_MethodAsync。

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

在前一個Task<TResult> 範例,您可以 Task_MethodAsync 從等候運算子的應用程式分隔對語彙基的呼叫,如下列程式碼所示。 不過,請記住 Task 沒有 Result 屬性,而且當等候運算子套用至 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 &= String.Format(vbCrLf & "Application can continue working while the Task runs. . . ." & vbCrLf)

Await simpleTask
// Call and await in separate statements.
Task simpleTask = Task_MethodAsync();

// You can do other work that does not rely on simpleTask before awaiting.
textBox1.Text += String.Format("\r\nApplication can continue working while the Task runs. . . .\r\n");

await simpleTask;

void 傳回型別

為 void 傳回型別 (在 Visual Basic 中的Sub 程序) 的主要用途是在事件處理常式,需要有 void 傳回型別。 void 傳回也可以用於覆寫會傳回空白的方法或實作活動,其活動可被分類為「發出和忘記」。不過,在中,因為傳回虛值(void)的非同步方法無法等候,您應該盡可能傳回 Task 。 這類方法的所有呼叫端必須可以繼續執行,不等候呼叫的非同步方法完成,而且呼叫端必須不受非同步方法產生任何值或例外狀況的影響。

傳回虛值的非同步方法的呼叫端不可攔截從方法擲回的例外狀況,因此,這類未處理的例外狀況可能會造成應用程式失敗。 如果例外狀況在傳回 TaskTask<TResult>的非同步方法發生,此例外會在傳回的工作重新儲存並重新擲出,當工作等候時。 因此,請確定可能會造成例外狀況的所有非同步方法有 TaskTask<TResult> 的傳回型別,而且對方法的呼叫會等候。

如需如何攔截發生在非同步方法的例外狀況的詳細資訊,請參閱 try-catch (C# 參考)Try...Catch...Finally 陳述式 (Visual Basic)

下列程式碼會定義一個非同步事件處理常式。

' 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
// VOID EXAMPLE
private async void button1_Click(object sender, RoutedEventArgs e)
{
    textBox1.Clear();

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

    // Say goodbye.
    textBox1.Text += "\r\nAll done, exiting button-click event handler.";
}

完整範例

下列 Windows Presentation Foundation (WPF) 專案包含本主題中的程式碼範例。

若要執行專案,請執行下列步驟:

  1. 啟動 Visual Studio。

  2. 在功能表列上,選擇 [檔案]、[新增]、[專案]。

    [新增專案] 對話方塊隨即開啟。

  3. 在 [安裝] 中, [ [範本] 分類中,選取 [Visual Basic] 或 [Visual C#]],然後選取 [視窗]。 從專案類型清單選取 [WPF 應用程式] 。

  4. 輸入 AsyncTracer 做為專案名稱,然後選取 [確定] 按鈕。

    新專案即會出現於 [方案總管] 中。

  5. 在 Visual Studio 程式碼編輯器中,選取 [MainWindow.xaml] 索引標籤。

    如果這個選項不可見,請開啟 MainWindow.xaml 的捷徑功能表上的 [方案總管]],然後選取 [開啟]。

  6. 在 MainWindow.xaml [XAML] 檢視中,以下列程式碼取代此程式碼。

    <Window x:Class="MainWindow"
            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="https://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>
    
    <Window x:Class="AsyncReturnTypes.MainWindow"
            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="https://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 或 MainWindow.xaml.cs 的捷徑功能表,然後選取 [檢視程式碼]。

  8. 在 MainWindow.xaml.vb 或 MainWindow.xaml.cs 中,以下列程式碼取代中的程式碼。

    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 &= String.Format("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 &= String.Format(vbCrLf & "Value of result1 variable:   {0}" & vbCrLf, result1)
            textBox1.Text &= String.Format("Value of result2 variable:   {0}" & vbCrLf, result2)
            textBox1.Text &= String.Format("Value of resultTask.Result:  {0}" & vbCrLf, integerTask.Result)
    
            ' 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 &= String.Format(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 &= String.Format(vbCrLf & "Sorry for the delay. . . ." & vbCrLf)
    
            ' This method has no return statement, so its return type is Task. 
        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;
    
    namespace AsyncReturnTypes
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            // VOID EXAMPLE
            private async void button1_Click(object sender, RoutedEventArgs e)
            {
                textBox1.Clear();
    
                // Start the process and await its completion. DriverAsync is a 
                // Task-returning async method.
                await DriverAsync();
    
                // Say goodbye.
                textBox1.Text += "\r\nAll done, exiting button-click event handler.";
            }
    
            async Task DriverAsync()
            {
                // Task<T> 
                // Call and await the Task<T>-returning async method in the same statement.
                int result1 = await TaskOfT_MethodAsync();
    
                // Call and await in separate statements.
                Task<int> integerTask = TaskOfT_MethodAsync();
    
                // You can do other work that does not rely on integerTask before awaiting.
                textBox1.Text += String.Format("Application can continue working while the Task<T> runs. . . . \r\n");
    
                int result2 = await integerTask;
    
                // Display the values of the result1 variable, the result2 variable, and
                // the integerTask.Result property.
                textBox1.Text += String.Format("\r\nValue of result1 variable:   {0}\r\n", result1);
                textBox1.Text += String.Format("Value of result2 variable:   {0}\r\n", result2);
                textBox1.Text += String.Format("Value of integerTask.Result: {0}\r\n", integerTask.Result);
    
                // Task
                // Call and await the Task-returning async method in the same statement.
                await Task_MethodAsync();
    
                // Call and await in separate statements.
                Task simpleTask = Task_MethodAsync();
    
                // You can do other work that does not rely on simpleTask before awaiting.
                textBox1.Text += String.Format("\r\nApplication can continue working while the Task runs. . . .\r\n");
    
                await simpleTask;
            }
    
            // TASK<T> EXAMPLE
            async Task<int> TaskOfT_MethodAsync()
            {
                // The body of the method is expected to contain an awaited asynchronous
                // call.
                // Task.FromResult is a placeholder for actual work that returns a string.
                var today = await Task.FromResult<string>(DateTime.Now.DayOfWeek.ToString());
    
                // The method then can process the result in some way.
                int leisureHours;
                if (today.First() == 'S')
                    leisureHours = 16;
                else
                    leisureHours = 5;
    
                // Because the return statement specifies an operand of type int, the
                // method must have a return type of Task<int>.
                return leisureHours;
            }
    
    
            // TASK EXAMPLE
            async Task Task_MethodAsync()
            {
                // 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);
                // Task.Delay delays the following line by two seconds.
                textBox1.Text += String.Format("\r\nSorry for the delay. . . .\r\n");
    
                // This method has no return statement, so its return type is Task.  
            }
        }
    }
    
  9. 選取 F5 鍵執行程式,然後選取 [開始] 按鈕。

    下列輸出應出現。

    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.
    

請參閱

工作

逐步解說:使用 Async 和 Await 存取 Web (C# 和 Visual Basic)

逐步解說:搭配非同步方法使用偵錯工具

參考

async (C# 參考)

Async (Visual Basic)

Await 運算子 (Visual Basic)

await (C# 參考)

FromResult<TResult>

概念

非同步程式中的控制流程 (C# 和 Visual Basic)