166 votes

avertissant que cet appel n'est pas attendu, l'exécution de la méthode courante continue

Je viens d'avoir VS2012 et j'essaie de me débrouiller avec async .

Disons que j'ai une méthode qui récupère une valeur à partir d'une source bloquante. Je ne veux pas que l'appelant de la méthode soit bloqué. Je pourrais écrire la méthode pour qu'elle prenne un callback qui est invoqué lorsque la valeur arrive, mais comme j'utilise C# 5, je décide de rendre la méthode asynchrone pour que les appelants n'aient pas à s'occuper des callbacks :

// contrived example (edited in response to Servy's comment)
public static Task<string> PromptForStringAsync(string prompt)
{
    return Task.Factory.StartNew(() => {
        Console.Write(prompt);
        return Console.ReadLine();
    });
}

Voici un exemple de méthode qui l'appelle. Si PromptForStringAsync n'était pas asynchrone, cette méthode nécessiterait d'imbriquer un callback dans un callback. Avec l'asynchronie, je peux écrire ma méthode de manière très naturelle :

public static async Task GetNameAsync()
{
    string firstname = await PromptForStringAsync("Enter your first name: ");
    Console.WriteLine("Welcome {0}.", firstname);

    string lastname = await PromptForStringAsync("Enter your last name: ");
    Console.WriteLine("Name saved as '{0} {1}'.", firstname, lastname);
}

Jusqu'à présent, tout va bien. Le problème est que lorsque je appelez GetNameAsync :

public static void DoStuff()
{
    GetNameAsync();
    MainWorkOfApplicationIDontWantBlocked();
}

Le but de GetNameAsync est que c'est asynchrone. Je n'ai pas quiere de la bloquer, car je veux retourner au MainWorkOfApplicationIDontWantBlocked dès que possible et laisser GetNameAsync faire son travail en arrière-plan. Cependant, l'appeler de cette façon me donne un avertissement du compilateur sur le fichier GetNameAsync ligne :

Warning 1   Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

Je suis parfaitement conscient que "l'exécution de la méthode en cours continue avant que l'appel ne soit terminé". C'est le point de code asynchrone, non ?

Je préfère que mon code soit compilé sans avertissement, mais il n'y a rien à "réparer" ici, car le code fait exactement ce que je veux qu'il fasse. Je peux me débarrasser de l'avertissement en stockant la valeur de retour de GetNameAsync :

public static void DoStuff()
{
    var result = GetNameAsync(); // supress warning
    MainWorkOfApplicationIDontWantBlocked();
}

Mais maintenant j'ai du code superflu. Visual Studio semble comprendre que j'ai été contraint d'écrire ce code inutile, car il supprime l'avertissement normal "valeur jamais utilisée".

Je peux aussi me débarrasser de l'avertissement en enveloppant GetNameAsync dans une méthode qui n'est pas asynchrone :

    public static Task GetNameWrapper()
    {
        return GetNameAsync();
    }

Mais c'est même plus code superflu. Je dois donc écrire du code dont je n'ai pas besoin ou tolérer un avertissement inutile.

Mon utilisation de l'asynchronisme est-elle incorrecte ?

7voto

lorddev Points 1459

Selon l'article de Microsoft sur cet avertissement, vous pouvez le résoudre en assignant simplement la tâche retournée à une variable. Vous trouverez ci-dessous une traduction du code fourni dans l'exemple de Microsoft :

    // 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, the recommended practice is always to
    // await a call to an async method.
    // Replace Call #1 with the following line.
    Task delayTask = CalledMethodAsync(delay);

Notez que si vous faites cela, vous obtiendrez le message "Local variable is never used" dans ReSharper.

4voto

JuanluElGuerre Points 77

Voici une solution simple.

public static class TasksExtensions
{
    public static void RunAndForget(this Task task)
    {
    }
}

Salutations

1voto

Guffa Points 308133

C'est votre exemple simplifié qui cause le code superflu. Normalement, vous voudriez utiliser les données qui ont été extraites de la source de blocage à un moment donné du programme, et vous voudriez donc récupérer le résultat pour pouvoir accéder aux données.

Si vous avez vraiment quelque chose qui se passe de manière totalement isolée du reste du programme, l'asynchronisme ne serait pas la bonne approche. Commencez simplement un nouveau fil de discussion pour cette tâche.

1voto

Simon Mourier Points 49585

Si vous ne voulez pas changer la signature de la méthode pour retourner void (comme le retour void devrait toujours être un void ed), vous pouvez utiliser C# 7.0+. Fonction de rejet comme ceci, ce qui est légèrement mieux que d'assigner à une variable (et devrait supprimer la plupart des avertissements des autres outils de validation des sources) :

public static void DoStuff()
{
    _ = GetNameAsync(); // we don't need the return value (suppresses warning)
    MainWorkOfApplicationIDontWantBlocked();
}

0voto

Jens Points 26

Voulez-vous vraiment ignorer le résultat ? comme par exemple ignorer toute exception inattendue ?

Si ce n'est pas le cas, vous pouvez vous pencher sur cette question : L'approche "Fire and Forget ,

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X