Suppression de «l’avertissement CS4014: cet appel n’étant pas attendu, l’exécution de la méthode en cours se poursuit…»

Ce n’est pas un doublon de “Comment appeler en toute sécurité une méthode asynchrone en C # sans attendre” .

Comment puis-je supprimer gentiment l’avertissement suivant?

warning CS4014: Cet appel n’étant pas attendu, l’exécution de la méthode en cours se poursuit avant la fin de l’appel. Pensez à appliquer l’opérateur “wait” au résultat de l’appel.

Un exemple simple:

static async Task WorkAsync() { await Task.Delay(1000); Console.WriteLine("Done!"); } static async Task StartWorkAsync() { WorkAsync(); // I want fire-and-forget // more unrelated async/await stuff here, eg: // ... await Task.Delay(2000); } 

Ce que j’ai essayé et n’a pas aimé:

 static async Task StartWorkAsync() { #pragma warning disable 4014 WorkAsync(); // I want fire-and-forget here #pragma warning restore 4014 // ... } static async Task StartWorkAsync() { var ignoreMe = WorkAsync(); // I want fire-and-forget here // ... } 

Vous pouvez créer une méthode d’extension qui empêchera l’avertissement. La méthode d’extension peut être vide ou vous pouvez append la gestion des exceptions avec .ContinueWith() .

 static class TaskExtensions { public static void Forget(this Task task) { task.ContinueWith( t => { WriteLog(t.Exception); }, TaskContinuationOptions.OnlyOnFaulted); } } public async Task StartWorkAsync() { this.WorkAsync().Forget(); } 

Cependant, ASP.NET compte le nombre de tâches en cours d’exécution. Par conséquent, il ne fonctionnera pas avec l’extension Forget() comme indiqué ci-dessus, mais peut échouer à l’exception de:

Un module ou un gestionnaire asynchrone s’est terminé pendant qu’une opération asynchrone était toujours en attente.

Avec .NET 4.5.2, il peut être résolu en utilisant HostingEnvironment.QueueBackgroundWorkItem :

 public static Task HandleFault(this Task task, CancellationToken cancelToken) { return task.ContinueWith( t => { WriteLog(t.Exception); }, cancelToken, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); } public async Task StartWorkAsync() { System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem( cancelToken => this.WorkAsync().HandleFault(cancelToken)); } 

Avec C # 7, vous pouvez maintenant utiliser les rejets :

 _ = WorkAsync(); 

Vous pouvez décorer la méthode avec l’atsortingbut suivant:

 [System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS4014:Await.Warning")] static async Task StartWorkAsync() { WorkAsync(); // ... } 

En gros, vous dites au compilateur que vous savez ce que vous faites et qu’il n’a pas besoin de s’inquiéter des erreurs possibles.

La partie importante de ce code est le deuxième paramètre. La partie “CS4014:” est ce qui supprime l’avertissement. Vous pouvez écrire tout ce que vous voulez sur le rest.

Mes deux manières de gérer cela.

Juste le supprimer

#pragma warning disable est une bonne solution pour “tirer et oublier”.

La raison pour laquelle cet avertissement existe est que, dans de nombreux cas, vous n’avez pas l’intention d’utiliser une méthode qui renvoie une tâche sans l’attendre. Supprimer l’avertissement lorsque vous avez l’intention de tirer et d’oublier a du sens.

Si vous avez du mal à vous souvenir de l’orthographe de #pragma warning disable 4014 , laissez simplement Visual Studio l’append pour vous. Appuyez sur Ctrl +. ouvrir “Actions rapides” puis “Supprimer CS2014”

Enregistrez-le dans une variable locale

Exemple

var task = Task.Run(() => DoMyStuff()).ConfigureAwait(false);

Comme il n’y a pas d’appel à la task , en mode Release, la variable locale doit être immédiatement optimisée, comme si elle n’y était jamais. En fait, je doute que le compilateur crée même la variable locale (Quelqu’un peut le confirmer avec un décompilateur).

En tout

Il est stupide de créer une méthode qui nécessite quelques tics supplémentaires pour supprimer un avertissement.

Un moyen facile d’arrêter l’avertissement est d’affecter simplement la tâche en l’appelant:

 Task fireAndForget = WorkAsync(); // No warning now 

Et donc, dans votre message original, vous feriez:

 static async Task StartWorkAsync() { // Fire and forget var fireAndForget = WorkAsync(); // Tell the comstackr you know it's a task that's being returned // more unrelated async/await stuff here, eg: // ... await Task.Delay(2000); } 

La raison de cet avertissement est que WorkAsync renvoie une tâche qui n’est jamais lue ou attendue. Vous pouvez désactiver le type de retour de WorkAsync et l’avertissement disparaîtra.

En règle générale, une méthode renvoie une tâche lorsque l’appelant doit connaître le statut du travailleur. Dans le cas d’un “fire-and-forget”, le vide devrait être renvoyé pour ressembler à ce que l’appelant est indépendant de la méthode appelée.

 static async void WorkAsync() { await Task.Delay(1000); Console.WriteLine("Done!"); } static async Task StartWorkAsync() { WorkAsync(); // no warning since return type is void // more unrelated async/await stuff here, eg: // ... await Task.Delay(2000); } 

Pourquoi ne pas l’envelopper dans une méthode asynchrone qui renvoie un vide? Un peu long mais toutes les variables sont utilisées.

 static async Task StartWorkAsync() { async void WorkAndForgetAsync() => await WorkAsync(); WorkAndForgetAsync(); // no warning } 

J’ai trouvé cette approche par accident aujourd’hui. Vous pouvez définir un délégué et atsortingbuer d’abord la méthode asynchrone au délégué.

  delegate Task IntermediateHandler(); static async Task AsyncOperation() { await Task.Yield(); } 

et l’appeler ainsi

 (new IntermediateHandler(AsyncOperation))(); 

J’ai pensé qu’il était intéressant que le compilateur ne donne pas exactement le même avertissement lors de l’utilisation du délégué.