C#——關鍵字:async
C#——關鍵字:async
async
使用 async 修飾符可將方法、lambda 表示式或匿名方法指定為非同步。 如果對方法或表示式使用此修飾符,則其稱為非同步方法 。 如下示例定義了一個名為 ExampleMethodAsync 的非同步方法:
public async Task<int> ExampleMethodAsync()
{
//...
}
如果不熟悉非同步程式設計,或者不瞭解非同步方法如何在不阻止呼叫方執行緒的情況下使用 await 運算子執行可能需要長時間執行的工作,請參閱使用 Async 和 Await 的非同步程式設計中的說明。 如下程式碼見於一種非同步方法中,且呼叫 HttpClient.GetStringAsync 方法:
string contents = await httpClient.GetStringAsync(requestUrl);
非同步方法同步執行,直至到達其第一個 await 表示式,此時會將方法掛起,直到等待的任務完成。 同時,如下節示例中所示,控制元件將返回到方法的呼叫方。
如果 async 關鍵字修改的方法不包含 await 表示式或語句,則該方法將同步執行。 編譯器警告將通知你不包含 await 語句的任何非同步方法,因為該情況可能表示存在錯誤。 請參閱編譯器警告(等級 1)CS4014。
async 關鍵字是上下文關鍵字,原因在於只有當它修飾方法、lambda 表示式或匿名方法時,它才是關鍵字。 在所有其他上下文中,都會將其解釋為識別符號。
示例
下面的示例展示了非同步事件處理程式 StartButton_Click 和非同步方法 ExampleMethodAsync 之間的控制結構和流程。 此非同步方法的結果是 Web 頁面的字元數。 此程式碼適用於在 Visual Studio 中建立的 Windows Presentation Foundation (WPF) 應用或 Windows 應用商店應用;請參見有關設定應用的程式碼註釋。
可以在 Visual Studio 中將此程式碼作為 Windows Presentation Foundation (WPF) 應用或 Windows 應用商店應用執行。 需要一個名為 StartButton 的按鈕控制元件和一個名為 ResultsTextBox 的文字框控制元件。 切勿忘記設定名稱和處理程式,以便獲得類似於以下程式碼的內容:
<Button Content="Button" HorizontalAlignment="Left" Margin="88,77,0,0" VerticalAlignment="Top" Width="75"
Click="StartButton_Click" Name="StartButton"/>
<TextBox HorizontalAlignment="Left" Height="137" Margin="88,140,0,0" TextWrapping="Wrap"
Text="<Enter a URL>" VerticalAlignment="Top" Width="310" Name="ResultsTextBox"/>
將程式碼作為 WPF 應用執行:
1.將此程式碼貼上到 MainWindow.xaml.cs 中的 MainWindow 類中。
2.新增對 System.Net.Http 的引用。
3.為 System.Net.Http 新增一個 using 指令。
將此程式碼作為 Windows 應用商店應用執行:
1.將此程式碼貼上到 MainPage.xaml.cs 中的 MainPage 類中。
2.為 System.Net.Http 和 System.Threading.Tasks 新增 using 指令。
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
// ExampleMethodAsync returns a Task<int>, which means that the method
// eventually produces an int result. However, ExampleMethodAsync returns
// the Task<int> value as soon as it reaches an await.
ResultsTextBox.Text += "\n";
try
{
int length = await ExampleMethodAsync();
// Note that you could put "await ExampleMethodAsync()" in the next line where
// "length" is, but due to when '+=' fetches the value of ResultsTextBox, you
// would not see the global side effect of ExampleMethodAsync setting the text.
ResultsTextBox.Text += String.Format("Length: {0:N0}\n", length);
}
catch (Exception)
{
// Process the exception if one occurs.
}
}
public async Task<int> ExampleMethodAsync()
{
var httpClient = new HttpClient();
int exampleInt = (await httpClient.GetStringAsync("http://msdn.microsoft.com")).Length;
ResultsTextBox.Text += "Preparing to finish ExampleMethodAsync.\n";
// After the following return statement, any method that's awaiting
// ExampleMethodAsync (in this case, StartButton_Click) can get the
// integer result.
return exampleInt;
}
// The example displays the following output:
// Preparing to finish ExampleMethodAsync.
// Length: 53292
重要
若要深入瞭解各項任務以及在等待任務期間所執行的程式碼,請參閱使用 Async 和 Await 的非同步程式設計。 有關使用類似元素的完整控制檯示例,請參閱在非同步任務完成時對其進行處理 (C#)。
返回型別
非同步方法可具有以下返回型別:
1.Task
2.Task<TResult>
3.void。 對於除事件處理程式以外的程式碼,通常不鼓勵使用 async void 方法,因為呼叫方不能 await 那些方法,並且必須實現不同的機制來報告成功完成或錯誤條件。
4.從 C# 7.0 開始,任何具有可訪問的 GetAwaiter 方法的型別。 System.Threading.Tasks.ValueTask<TResult> 型別屬於此類實現。 它通過新增 NuGet 包 System.Threading.Tasks.Extensions 的方式可用。
此非同步方法既不能宣告任何 in、ref 或 out 引數,也不能具有引用返回值,但它可以呼叫具有此類引數的方法。
如果非同步方法的 語句指定一個 型別的運算元,則應指定 Task 作為方法的返回型別TResult。 如果當方法完成時未返回有意義的值,則應使用 Task。 即,對方法的呼叫將返回一個 Task,但是當 Task 完成時,任何等待 await 的所有 Task 表示式的計算結果都為 void。
你應主要使用 void 返回型別來定義事件處理程式,這些處理程式需要此返回型別。 void 返回非同步方法的呼叫方不能等待,並且無法捕獲該方法引發的異常。
從 C# 7.0 開始,返回另一個型別(通常為值型別),該型別具有 GetAwaiter 方法,可儘可能減少效能關鍵程式碼段中的記憶體分配。
有關詳細資訊和示例,請參閱非同步返回型別。