Dans Scala, il existe une classe Promise qui peut être utilisée pour compléter manuellement un avenir. Je recherche une alternative en C #.
J'écris un test et je veux qu'il ressemble à ceci:
// var MyResult has a field `Header`
var promise = new Promise<MyResult>;
handlerMyEventsWithHandler( msg =>
promise.Complete(msg);
);
// Wait for 2 seconds
var myResult = promise.Future.Await(2000);
Assert.Equals("my header", myResult.Header);
Je comprends que ce n’est probablement pas le bon modèle pour C #, mais je ne pouvais pas trouver un moyen raisonnable d’obtenir la même chose, même avec un modèle quelque peu différent.
EDIT: veuillez noter que async
/await
ne m'aide pas ici, car je n'ai pas de tâche à attendre! Je viens d'avoir un accès à un gestionnaire qui sera exécuté sur un autre thread.
En C #:
Task<T>
est un avenir (ou Task
pour un avenir à unités revenant).TaskCompletionSource<T>
c'est une promesse.Donc, votre code se traduirait comme tel:
// var promise = new Promise<MyResult>;
var promise = new TaskCompletionSource<MyResult>();
// handlerMyEventsWithHandler(msg => promise.Complete(msg););
handlerMyEventsWithHandler(msg => promise.TrySetResult(msg));
// var myResult = promise.Future.Await(2000);
var completed = await Task.WhenAny(promise.Task, Task.Delay(2000));
if (completed == promise.Task)
; // Do something on timeout
var myResult = await completed;
Assert.Equals("my header", myResult.Header);
"L'attente asynchrone temporisée" est un peu gênante, mais elle est également relativement rare dans le code du monde réel. Pour les tests unitaires, je voudrais simplement faire une attente asynchrone régulière:
var promise = new TaskCompletionSource<MyResult>();
handlerMyEventsWithHandler(msg => promise.TrySetResult(msg));
var myResult = await promise.Task;
Assert.Equals("my header", myResult.Header);
L'équivalent approximatif de C # sans les bibliothèques tierces serait:
// var MyResult has a field `Header`
var promise = new TaskCompletionSource<MyResult>();
handlerMyEventsWithHandler(msg =>
promise.SetResult(msg)
);
// Wait for 2 seconds
if (promise.Task.Wait(2000))
{
var myResult = promise.Task.Result;
Debug.Assert("my header" == myResult.Header);
}
Notez qu'il est généralement préférable d'utiliser await
/async
à un niveau aussi élevé que possible. Accéder à la Result
d'un Task
ou utiliser Wait
peut dans certains cas introduire des blocages .
Vous pouvez utiliser la bibliothèque C # Promises
Open source sur Github: https://github.com/Real-Serious-Games/C-Sharp-Promise
Disponible sur NuGet: https://www.nuget.org/packages/RSG.Promise/
C'est la vieille façon de faire des promesses.
À l'époque, je crois que cela s'appelait la synchronisation :)
MyResult result = null;
var are = new AutoResetEvent(false);
handlerMyEventsWithHandler(
msg => {result = msg; are.Set();}
);
// Wait for 2 seconds
if(!are.WaitOne(2000)) {/* handle timeout... */}
Assert.Equals("my header", myResult.Header);
Juste pour être complet - trop grand pour un commentaire.
Je suis d'accord avec réponse de Stephen Cleary .
Mais si vous construisez une façade autour d'un code hérité, vous pouvez l'utiliser pour intégrer d'anciennes API dans une tâche telle que:
public Task<MyResult> GetResultAsync() {
MyResult result = null;
var are = new AutoResetEvent(false);
handlerMyEventsWithHandler(msg => {
result = msg;
are.Set();
});
are.WaitOne();
return Task.FromResult(result);
}
Essayez de regarder dans le modèle asynchrone. Les tâches sont l'équivalent le plus proche en c #.
Voici un lien vers un article de Microsoft expliquant leur utilisation.