コンパイラの警告 (レベル 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 ディレクティブを使用してコンパイラの警告を抑制することもできます。

次のコンソール アプリケーションには、前の例のメソッドが含まれています。 このアプリケーションを設定するには、次の手順を実行します。

  1. コンソール アプリケーションを作成し、それに AsyncWarning という名前を付けます。

  2. Visual Studio Code エディターで、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 キーを選択し、プログラムを実行します。

想定される出力がコードの最後に表示されます。

関連項目