共用方式為


編譯器警告 (層級 1) CS4014

因為未等候此呼叫,所以在呼叫完成之前會繼續執行目前的方法。 請考慮將 await 運算子套用至呼叫的結果。

目前的方法會呼叫傳回 TaskTask<TResult> 且不會將 await 運算子套用至結果的非同步方法。 非同步方法的呼叫會啟動非同步工作。 不過,由於不會套用任何 await 運算子,因此程式會繼續執行,而不等候工作完成。 在大部分情況下,該行為並非您所預期。 通常呼叫方法的其他方面取決於呼叫的結果,或至少被呼叫的方法必須完成,才能從包含呼叫的方法傳回。

同樣重要的問題是,在呼叫的非同步方法中引發的例外狀況會發生什麼情形。 在傳回 TaskTask<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 指示詞隱藏編譯器警告。

範例

下列主控台應用程式包含了前述範例的方法。 下列步驟將會設定應用程式。

  1. 建立主控台應用程式,並命名為 AsyncWarning

  2. 在 Visual Studio 程式碼編輯器中,選擇 [Program.cs] 索引標籤。

  3. 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.
    }
    
  4. 選取 F5 鍵以執行程式。

預期的輸出會出現在程式碼結尾。

另請參閱