Je travaille avec une fenêtre d'alerte (Telerik WPF) qui est normalement affichée de manière asynchrone (le code continue de fonctionner pendant qu'il est ouvert) et je veux le rendre synchrone en utilisant async/wait.
J'ai ce travail avec TaskCompletionSource
mais cette classe est générique et retourne un objet comme Task<bool>
quand tout ce que je veux, c'est un simple Task
sans valeur de retour.
public Task<bool> ShowAlert(object message, string windowTitle)
{
var dialogParameters = new DialogParameters { Content = message };
var tcs = new TaskCompletionSource<bool>();
dialogParameters.Closed += (s, e) => tcs.TrySetResult(true);
RadWindow.Alert(dialogParameters);
return tcs.Task;
}
Le code qui appelle cette méthode est
await MessageBoxService.ShowAlert("The alert text.")
Comment puis-je retourner une tâche non générique qui fonctionne de la même manière que je peux attendre jusqu'à ce que le dialogParameters.Closed
un événement se déclenche? Je comprends que je pourrais simplement ignorer le bool
qui est renvoyé dans ce code. Je cherche une solution différente de cela.
La méthode peut être modifiée pour:
public Task ShowAlert(object message, string windowTitle)
Task<bool>
hérite de Task
pour que vous puissiez retourner Task<bool>
tout en exposant uniquement Task
à l'appelant
Modifier:
J'ai trouvé un document Microsoft, http://www.Microsoft.com/en-us/download/details.aspx?id=19957 , par Stephen Toub intitulé "Le modèle asynchrone basé sur les tâches" et il a l'extrait suivant qui recommande ce même modèle.
Il n'y a pas d'homologue non générique à TaskCompletionSource <TResult>. Cependant, Task <TResult> dérive de Task, et donc le TaskCompletionSource <TResult> générique peut être utilisé pour les méthodes liées aux E/S qui renvoient simplement une Task en utilisant une source avec un TResult factice (Boolean est un bon choix par défaut, et si un développeur s'inquiète pour un consommateur de la tâche de le convertir en tâche <TResult>, un type de TResult privé peut être utilisé)
Si vous ne souhaitez pas divulguer d'informations, l'approche courante consiste à utiliser TaskCompletionSource<object>
et complet avec un résultat de null
. Ensuite, renvoyez-le simplement en tant que Task
.
Nito.AsyncEx implémente une classe TaskCompletionSource
non générique, crédit à Mr @StephenCleary ci-dessus.
De @Kevin Kalitowski
J'ai trouvé un document Microsoft, http://www.Microsoft.com/en-us/download/details.aspx?id=19957 , par Stephen Toub intitulé "Le modèle asynchrone basé sur les tâches"
Il y a un exemple dans ce document qui, je pense, traite de la question comme le souligne Kevin. Voici l'exemple:
public static Task Delay(int millisecondsTimeout)
{
var tcs = new TaskCompletionSource<bool>();
new Timer(self =>
{
((IDisposable)self).Dispose();
tcs.TrySetResult(true);
}).Change(millisecondsTimeout, -1);
return tcs.Task;
}
Au début, je pensais que ce n'était pas bon car vous ne pouvez pas ajouter directement le modificateur "async" à la méthode sans message de compilation. Mais, si vous modifiez légèrement la méthode, la méthode se compilera avec async/wait:
public async static Task Delay(int millisecondsTimeout)
{
var tcs = new TaskCompletionSource<bool>();
new Timer(self =>
{
((IDisposable)self).Dispose();
tcs.TrySetResult(true);
}).Change(millisecondsTimeout, -1);
await tcs.Task;
}
Edit: au début, je pensais avoir surmonté la bosse. Mais, lorsque j'ai exécuté le code équivalent dans mon application, ce code fait simplement que l'application se bloque lorsqu'elle attend tcs.Task ;. Donc, je crois toujours que c'est une grave faille de conception dans la syntaxe async/wait c #.