編譯器警告 (層級 1) CS4014
因為未等候此呼叫,所以在呼叫完成之前會繼續執行目前的方法。 請考慮將 await
運算子套用至呼叫的結果。
目前的方法會呼叫傳回 Task 或 Task<TResult> 且不會將 await 運算子套用至結果的非同步方法。 非同步方法的呼叫會啟動非同步工作。 不過,由於不會套用任何 await
運算子,因此程式會繼續執行,而不等候工作完成。 在大部分情況下,該行為並非您所預期。 通常呼叫方法的其他方面取決於呼叫的結果,或至少被呼叫的方法必須完成,才能從包含呼叫的方法傳回。
同樣重要的問題是,在呼叫的非同步方法中引發的例外狀況會發生什麼情形。 在傳回 Task 或 Task<TResult> 的方法中引發的例外狀況會儲存到傳回的工作中。 如果您未等候工作,也未明確檢查例外狀況,例外狀況就會遺失。 如果您等候工作,則其例外狀況會再次擲回。
因此最佳做法是一律等候呼叫。
只有在您確定不要等候非同步呼叫完成,而且被呼叫的方法不會引發任何例外狀況時,才應考慮隱藏警告。 在這種情況下,您可以藉由將呼叫的工作結果指定至變數來隱藏警告。
下列範例將示範如何產生警告、如何隱藏警告,以及如何等候呼叫。
static async Task CallingMethodAsync(int millisecondsDelay)
{
Console.WriteLine(" Entering calling method.");
// Call #1.
// Call an async method. Because you don't await it, its completion
// isn't coordinated with the current method, CallingMethodAsync.
// The following line causes warning CS4014.
CalledMethodAsync(millisecondsDelay);
// Call #2.
// To suppress the warning without awaiting, you can assign the
// returned task to a variable. The assignment doesn't change how
// the program runs. However, recommended practice is always to
// await a call to an async method.
// Replace Call #1 with the following line.
// Task delayTask = CalledMethodAsync(millisecondsDelay);
// Call #3
// To contrast with an awaited call, replace the unawaited call
// (Call #1 or Call #2) with the following awaited call. Best
// practice is to await the call.
// await CalledMethodAsync(millisecondsDelay);
Console.WriteLine(" Returning from calling method.");
}
static async Task CalledMethodAsync(int millisecondsDelay)
{
Console.WriteLine(" Entering called method, starting and awaiting Task.Delay.");
await Task.Delay(millisecondsDelay);
Console.WriteLine(" Task.Delay is finished--returning from called method.");
}
在此範例中,如果您選擇呼叫 #1 或呼叫 #2,則未等候的非同步方法 (CalledMethodAsync
) 會在其呼叫端 (CallingMethodAsync
) 和呼叫端的呼叫端都完成之後才完成。 下列輸出的最後一行將顯示被呼叫的方法完成的時間。 輸入中會標記在完整範例中進入和結束呼叫 CallingMethodAsync
的事件處理常式。
Entering the Click event handler.
Entering calling method.
Entering called method, starting and awaiting Task.Delay.
Returning from calling method.
Exiting the Click event handler.
Task.Delay is finished--returning from called method.
您也可以使用 #pragma warning 指示詞隱藏編譯器警告。
範例
下列主控台應用程式包含了前述範例的方法。 下列步驟將會設定應用程式。
建立主控台應用程式,並命名為
AsyncWarning
。在 Visual Studio 程式碼編輯器中,選擇 [Program.cs] 索引標籤。
將 Program.cs 中的程式碼取代為下列程式碼。
using System; using System.Threading.Tasks; namespace AsyncWarning { class Program { static async Task Main() { Console.WriteLine("Entering Main() application entry point."); int millisecondsDelay = 2000; await CallingMethodAsync(millisecondsDelay); Console.WriteLine("Exiting Main() application entry point."); await Task.Delay(millisecondsDelay + 500); } static async Task CallingMethodAsync(int millisecondsDelay) { Console.WriteLine(" Entering calling method."); // Call #1. // Call an async method. Because you don't await it, its completion // isn't coordinated with the current method, CallingMethodAsync. // The following line causes warning CS4014. // CalledMethodAsync(millisecondsDelay); // Call #2. // To suppress the warning without awaiting, you can assign the // returned task to a variable. The assignment doesn't change how // the program runs. However, recommended practice is always to // await a call to an async method. // Replace Call #1 with the following line. //Task delayTask = CalledMethodAsync(millisecondsDelay); // Call #3 // To contrast with an awaited call, replace the unawaited call // (Call #1 or Call #2) with the following awaited call. Best // practice is to await the call. // await CalledMethodAsync(millisecondsDelay); Console.WriteLine(" Returning from calling method."); } static async Task CalledMethodAsync(int millisecondsDelay) { Console.WriteLine(" Entering called method, starting and awaiting Task.Delay."); await Task.Delay(millisecondsDelay); Console.WriteLine(" Task.Delay is finished--returning from called method."); } } // Output with Call #1 or Call #2. (Wait for the last line to appear.) // Entering Main() application entry point. // Entering calling method. // Entering called method, starting and awaiting Task.Delay. // Returning from calling method. // Exiting Main() application entry point. // Task.Delay is finished--returning from called method. // Output with Call #3, which awaits the call to CalledMethodAsync. // Entering Main() application entry point. // Entering calling method. // Entering called method, starting and awaiting Task.Delay. // Task.Delay is finished--returning from called method. // Returning from calling method. // Exiting Main() application entry point. }
選取 F5 鍵以執行程式。
預期的輸出會出現在程式碼結尾。