非同步方法的傳回類型 (C# and Visual Basic)
Async 方法有三個可能的傳回類型:Task、Task 和 void。 在 Visual Basic 中,void 傳回類型會撰寫為 Sub 程序。 如需非同步方法的詳細資訊,請參閱使用 Async 和 Await 設計非同步程式 (C# 和 Visual Basic)。
每個傳回類型都是在下列其中一個區段中進行檢查,您可以在本主題的結尾找到使用全部三種類型的完整範例。
注意事項 |
---|
若要執行範例,您必須將 Visual Studio 2012、Visual Studio 2013、Visual Studio Express 2012 for Windows Desktop、Visual Studio Express 2013 for Windows 或 .NET Framework 4.5 或 4.5.1 安裝在您的電腦上。 |
本主題包含下列章節。
- 工作(T) 傳回類型
- 工作傳回類型
- void 傳回類型
- 完整範例
- 相關主題
工作(T) 傳回類型
Task 傳回類型用於非同步方法,其包含 Return (Visual Basic) 或 return (C#) 陳述式,運算元的類型為 TResult。
在下列範例中,TaskOfT_MethodAsync 非同步方法包含傳回整數的傳回陳述式。 因此,方法宣告必須在 Visual Basic 中指定傳回類型 Task(Of Integer) ,或在 C# 中指定傳回類型 Task<int> 。
' 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的應用程式,如下列程式碼所示。 對不是立即等候之方法 TaskOfT_MethodAsync 的呼叫會傳回 Task(Of Integer) 或 Task<int>,如您對方法的宣告所預期的。 工作指派至範例中的 integerTask 變數。 由於 integerTask 是 Task,其包含屬於類型 TResult 的 Result 屬性。 在這種情況下,TResult 代表整數類型。 當 Await 或 await 套用至 integerTask時,等候運算式為 integerTask之Result 屬性的內容。 此值已被指派給 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);
工作傳回類型
不包含傳回陳述式或包含傳回陳述式但不傳回運算元的 Async 方法,通常具有 Task 傳回類型。 如果撰寫為同步執行,這類方法會是傳回 Void 的方法 (在 Visual Basic 中是 Sub 程序)。 如果您提供非同步方法使用 Task 傳回類型,則呼叫方法可以使用 await 運算子暫停呼叫端的完成,直到被呼叫非同步方法完成。
在下列範例中,非同步方法 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 或傳回 Void 的方法的呼叫陳述式。 在這種情況下,等候運算子的應用程式不會產生值。
下列程式碼會呼叫並等候方法 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 範例,您可以將對 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 的方法或執行可分類為「射後不理」(Fire and Forget) 之活動的方法。不過,因為傳回 void 的非同步方法無法等候,您應該盡可能傳回 Task 。 這類方法的所有呼叫端必須可以繼續執行,不等候呼叫的非同步方法完成,而且呼叫端必須不受非同步方法產生的任何值或例外狀況影響。
傳回 Void 非同步方法的呼叫端不可攔截從方法擲回的例外狀況,這類未處理的例外狀況可能會造成應用程式失敗。 如果例外狀況在傳回 Task 或 Task的非同步方法發生,當工作等候時,例外狀況會在傳回的工作中儲存並重新擲出。 因此,請確定可能會造成例外狀況的所有非同步方法有 Task 或 Task 的傳回類型,而且對方法的呼叫會等候。
如需如何攔截發生在非同步方法的例外狀況的詳細資訊,請參閱 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) 專案包含本主題中的程式碼範例。
若要執行專案,請執行下列步驟:
啟動 Visual Studio。
在功能表列上,選擇 [檔案]、[新增]、[專案]。
[新增專案] 對話方塊隨即開啟。
在 [已安裝的]、[範本] 分類中,選擇 [Visual Basic] 或 [Visual C#],然後選擇 [Windows]。 從專案類型清單中選擇 [WPF 應用程式]。
輸入 AsyncReturnTypes 做為專案名稱,然後選擇 [確定] 按鈕。
新專案即會出現於 [方案總管] 中。
在 Visual Studio 程式碼編輯器中,選擇 [MainWindow.xaml] 索引標籤。
如果未顯示索引標籤,請在 [方案總管] 中開啟 MainWindow.xaml 的捷徑功能表,然後選擇 [開啟]。
在 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 的 [設計] 檢視中。
在 [方案總管] 中,開啟 MainWindow.xaml.vb 或 MainWindow.xaml.cs 的捷徑功能表,然後選擇 [檢視程式碼]。
將 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. } } }
選取 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)