コンパイラの警告 (レベル 1) CS4014
この呼び出しは待機されなかったため、現在のメソッドの実行は呼び出しの完了を待たずに続行されます。呼び出しの結果に 'await' 演算子を適用することを検討してください。
現在のメソッドは Task または Task を返し、結果に 待機します。 の演算子を加えない async メソッドを呼び出します。 async メソッドの呼び出しが非同期タスクを開始します。 ただし、await の演算子が適用されないため、プログラムにより、タスクの完了を待たずに従います。 ほとんどの場合、この処理は必要ではありません。 通常のメソッド呼び出しのそのほかの部分は、呼び出しの結果に依存するまたは呼び出しを含むメソッドから戻る前に、少なくとも、呼び出されたメソッドが完了すると想定されます。
同様に重要な問題は、非同期のメソッドで発生させる例外がどうなることです。 Task または Task を返すメソッドで発生させる例外は、返されたタスクに格納されます。 タスクを待たないし、例外を明示的にチェックしない場合、例外は失われます。 タスクを待てば、再度例外がスローされます。
ベスト プラクティスとして、呼び出しを常に待機する必要があります。
非同期呼び出しが完了するまで待機したくない場合、呼び出されたメソッドは例外を発生させないことを確認した場合のみに警告を抑制することを検討してください。 この場合、変数の呼び出しのタスクの結果を代入すると、この警告を抑制できます。
次の例では警告を、それが発生する方法と、呼び出しを抑制する方法を待機する方法を示します。
async Task CallingMethodAsync()
{
resultsTextBox.Text += "\r\n Entering calling method.";
// Variable delay is used to slow down the called method so that you can
// distinguish between awaiting and not awaiting in the program's output.
// You can adjust the value to produce the output that this topic shows
// after the code.
var delay = 5000;
// 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(delay);
// 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(delay);
// 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(delay);
// If the call to CalledMethodAsync isn't awaited, CallingMethodAsync
// continues to run and, in this example, finishes its work and returns
// to its caller.
resultsTextBox.Text += "\r\n Returning from calling method.";
}
async Task CalledMethodAsync(int howLong)
{
resultsTextBox.Text +=
"\r\n Entering called method, starting and awaiting Task.Delay.";
// Slow the process down a little so that you can distinguish between
// awaiting and not awaiting in the program's output. Adjust the value
// for howLong if necessary.
await Task.Delay(howLong);
resultsTextBox.Text +=
"\r\n Task.Delay is finished--returning from called method.";
}
例では、呼び出し #1 を選択または番号を呼び出すと、呼び出し元 (CallingMethodAsync) と呼び出し元の呼び出し元 (両方startButton_Click) の後の unawaited async メソッド (CalledMethodAsync) の完了が完了します。 次の出力の最後の行には、呼び出されたメソッドが終了すると表示されます。 エントリへの、完全なコード例の 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 警告 (C# リファレンス) のディレクティブを使用してコンパイラの警告を抑制できます。
使用例
Windows Presentation Foundation (WPF) の次のアプリケーションでは、上記の例のメソッドが含まれています。 次の手順は、アプリケーションが設定されます。
Create a WPF アプリケーションは、それを AsyncWarningという名前にします。
Visual Studio コード エディターで、[MainWindow.xaml] タブをクリックします。
タブが表示されていない場合は、[ソリューション エクスプローラー] の MainWindow.xaml のショートカット メニューを開き、[コードの表示] をクリックします。
次のコードでは、MainWindow.xaml の [XAML] ビューでコードを置き換えます。
<Window x:Class="AsyncWarning.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="startButton" Content="Start" HorizontalAlignment="Left" Margin="214,28,0,0" VerticalAlignment="Top" Width="75" HorizontalContentAlignment="Center" FontWeight="Bold" FontFamily="Aharoni" Click="startButton_Click" /> <TextBox x:Name="resultsTextBox" Margin="0,80,0,0" TextWrapping="Wrap" FontFamily="Lucida Console"/> </Grid> </Window>
ボタンやテキスト ボックスなどの単純なウィンドウは、MainWindow.xaml の [デザイン] ビューで表示されます。
XAML Designer に関する詳細については、「XAML デザイナーを使用した UI の作成」を参照してください。 独自の単純な UI を作成する方法の詳細については」、WPF アプリケーションを作成するために「単純な WPF MainWindow」をデザインするに チュートリアル: Async と Await を使用した Web へのアクセス (C# および Visual Basic)の「を参照してください。
次のコードで MainWindow.xaml.cs のコードを置き換えます。
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 AsyncWarning { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void startButton_Click(object sender, RoutedEventArgs e) { resultsTextBox.Text += "\r\nEntering the Click event handler."; await CallingMethodAsync(); resultsTextBox.Text += "\r\nExiting the Click event handler."; } async Task CallingMethodAsync() { resultsTextBox.Text += "\r\n Entering calling method."; // Variable delay is used to slow down the called method so that you can // distinguish between awaiting and not awaiting in the program's output. // You can adjust the value to produce the output that this topic shows // after the code. var delay = 5000; // 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(delay); // 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(delay); // 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(delay); // If the call to CalledMethodAsync isn't awaited, CallingMethodAsync // continues to run and, in this example, finishes its work and returns // to its caller. resultsTextBox.Text += "\r\n Returning from calling method."; } async Task CalledMethodAsync(int howLong) { resultsTextBox.Text += "\r\n Entering called method, starting and awaiting Task.Delay."; // Slow the process down a little so that you can distinguish between // awaiting and not awaiting in the program's output. Adjust the value // for howLong if necessary. await Task.Delay(howLong); resultsTextBox.Text += "\r\n Task.Delay is finished--returning from called method."; } } // Output with Call #1 or Call #2. (Wait for the last line to appear.) // 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. // Output with Call #3, which awaits the call to CalledMethodAsync. // Entering the Click event handler. // Entering calling method. // Entering called method, starting and awaiting Task.Delay. // Task.Delay is finished--returning from called method. // Returning from calling method. // Exiting the Click event handler. }
F5 キーを押してプログラムを実行し、[Start] を複数回クリックします。
予想される出力はコードの最後に表示されます。