In Scala gibt es eine Promise-Klasse, mit der eine Zukunft manuell abgeschlossen werden kann. Ich suche nach einer Alternative in C #.
Ich schreibe einen Test und möchte, dass er ungefähr so aussieht:
// 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);
Ich verstehe, dass dies wahrscheinlich nicht das richtige Muster für C # ist, aber ich konnte keinen vernünftigen Weg finden, um dasselbe auch mit etwas anderem Muster zu erreichen.
EDIT: bitte beachten Sie, dass async
/ await
hier nicht hilft, da ich keine Aufgabe zu erwarten habe! Ich habe nur Zugriff auf einen Handler, der auf einem anderen Thread ausgeführt wird.
Task<T>
.Antworten:
In C #:
Task<T>
ist eine Zukunft (oderTask
für eine Zukunft, die eine Einheit zurückgibt).TaskCompletionSource<T>
ist ein Versprechen.Ihr Code würde also als solcher übersetzt:
// 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);
Das "zeitgesteuerte asynchrone Warten" ist etwas umständlich, aber auch im realen Code relativ selten. Für Unit-Tests würde ich nur regelmäßig asynchron warten:
var promise = new TaskCompletionSource<MyResult>(); handlerMyEventsWithHandler(msg => promise.TrySetResult(msg)); var myResult = await promise.Task; Assert.Equals("my header", myResult.Header);
quelle
Das grobe C # -Äquivalent ohne Bibliotheken von Drittanbietern wäre:
// 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); }
Beachten Sie, dass es normalerweise am besten ist, das
await
/async
auf einen möglichst hohen Pegel zu setzen. Der ZugriffResult
auf einTask
oder die VerwendungWait
kann in einigen Fällen zu Deadlocks führen .quelle
Sie können die C # Promises-Bibliothek verwenden
Open Source auf Github: https://github.com/Real-Serious-Games/C-Sharp-Promise
Verfügbar bei NuGet: https://www.nuget.org/packages/RSG.Promise/
quelle
Dies ist die alte Art, Versprechen zu machen.
Damals glaube ich, dass es Synchronisation genannt wurde :)
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);
Nur der Vollständigkeit halber - zu groß für einen Kommentar.
Ich stimme Stephen Clearys Antwort zu .
Wenn Sie jedoch eine Fassade um einen alten Code erstellen, können Sie damit alte APIs in eine Aufgabe wie die folgenden einbinden:
public Task<MyResult> GetResultAsync() { MyResult result = null; var are = new AutoResetEvent(false); handlerMyEventsWithHandler(msg => { result = msg; are.Set(); }); are.WaitOne(); return Task.FromResult(result); }
quelle
Versuchen Sie, das asynchrone Modell zu untersuchen. Aufgaben sind das nächste Äquivalent in c #.
Hier ist ein Link zu einem MS-Artikel, in dem deren Verwendung erläutert wird.
quelle
Sie können das zukünftige Paket ( https://www.nuget.org/packages/Future/ ) von Nuget herunterladen und wie folgt verwenden
Promise<int> promise = new Promise<int>(); new Task(() => { Thread.Sleep(100); promise.Set(20); }).Start(); int result=promise.Get();
Gemäß dem Beispiel können Sie ein Versprechungsobjekt erstellen und ein Get-to-Get-Ergebnis ausführen. Get wartet, bis sich das Ergebnis auf dem Objekt befindet. Sie erstellen einen Satz aus einem anderen Thread, wie im obigen Beispiel gezeigt.
Dieses Paket enthält die folgenden zwei Klassen
Versprechen: Was auf unbestimmte Zeit auf das Ergebnis wartet
TimedPromise: Wartet nur bis zur angegebenen Zeit auf das Ergebnis. Wenn das Ergebnis in der Zeit nicht verfügbar ist, wird eine Timeout-Ausnahme ausgelöst
quelle