Je viens de recevoir VS2012 et j'essaie de comprendre async
.
Disons que j'ai une méthode qui récupère une valeur à partir d'une source de blocage. Je ne veux pas que l'appelant de la méthode bloque. Je pourrais écrire la méthode pour prendre un rappel qui est appelé lorsque la valeur arrive, mais comme j'utilise C # 5, je décide de rendre la méthode asynchrone afin que les appelants n'aient pas à gérer les rappels:
// 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 ce PromptForStringAsync
n'était pas asynchrone, cette méthode nécessiterait l'imbrication d'un rappel dans un rappel. Avec async, j'écris ma méthode de cette 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'ici tout va bien. Le problème est lorsque j'appelle GetNameAsync:
public static void DoStuff()
{
GetNameAsync();
MainWorkOfApplicationIDontWantBlocked();
}
Tout l'intérêt de GetNameAsync
est qu'il est asynchrone. Je ne veux pas qu'il se bloque, car je veux revenir à 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 la 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 actuelle se poursuit avant que l'appel ne soit terminé". C'est le but du code asynchrone, non?
Je préfère que mon code compile sans avertissements, mais il n'y a rien à "corriger" ici car le code fait exactement ce que je compte faire. 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é obligé d'écrire ce code inutile, car il supprime l'avertissement normal «valeur jamais utilisée».
Je peux également 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 du code encore plus superflu. Je dois donc écrire du code dont je n'ai pas besoin ou que je tolère un avertissement inutile.
Y a-t-il quelque chose dans mon utilisation de l'async qui ne va pas ici?
GetNameAsync
fournir le nom complet qui a été fourni par l'utilisateur ( par exemple Task<Name>
, plutôt que de retourner un Task
? DoStuff
Pourrait alors stocker cette tâche, et soit await
il après l'autre méthode, ou même passer la tâche à l'autre méthode de sorte qu'il pourrait await
ou Wait
quelque part à l' intérieur de la mise en œuvre de ce.
async
mot - clé.
PromptForStringAsync
vous faites plus de travail que nécessaire; renvoyez simplement le résultat deTask.Factory.StartNew
. C'est déjà une tâche dont la valeur est la chaîne saisie dans la console. Il n'est pas nécessaire de l'attendre pour renvoyer le résultat; cela n'ajoute aucune valeur nouvelle.