2016-08-17 17 views
30

W programie Scala istnieje klasa Obietnica, która może być używana do ręcznego uzupełniania Przyszłości. Szukam alternatywy w języku C#.Równoważnik obiecywania w języku C#

piszę test i chcę wyglądać to mniej więcej tak:

// 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); 

Rozumiem, że prawdopodobnie nie jest to prawo wzorzec dla C#, ale nie mogłem wymyślić rozsądny sposób osiągnąć to samo, nawet przy nieco odmiennym schemacie.

EDYCJA: należy pamiętać, że async/await nie pomoże tutaj, ponieważ nie mam zadania do czekania! Po prostu mam dostęp do programu obsługi, który będzie uruchamiany w innym wątku.

+0

Możliwa duplikat [jak i kiedy używać \ 'asynchroniczny \' i \ '\' czekają] (http://stackoverflow.com/questions/14455293/how-and-when-to-use-async-and-aait) – Stijn

+1

Myślę, że szukasz 'Task '. –

Odpowiedz

41

C#:

  • Task<T> jest zapłata (lub Task na przyszłość funduszem powrocie).
  • TaskCompletionSource<T> to obietnica.

Więc twój kod będzie przetłumaczyć jako takie:

// 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); 

W „czasowym asynchroniczny czekać” jest nieco niewygodne, ale to jest również stosunkowo rzadkie w kodzie w świecie rzeczywistym. Dla testów jednostkowych, chciałbym po prostu robić regularne oczekiwania asynchronicznego:

var promise = new TaskCompletionSource<MyResult>(); 

handlerMyEventsWithHandler(msg => promise.TrySetResult(msg)); 

var myResult = await promise.Task; 

Assert.Equals("my header", myResult.Header); 
+0

Istnieje lepszy sposób na wprowadzenie limitu czasu przy użyciu tokenów anulowania. Zobacz https://stackoverflow.com/q/23476576/1288449 –

+1

@StevenLiekens: Zgadzam się, że limity czasu są zazwyczaj lepiej reprezentowane jako żetony anulowania; Jest to jednak najlepsze rozwiązanie w sytuacjach, w których przekroczenia czasu są używane do anulowania operacji. W tym scenariuszu mówimy o anulowaniu operacji * wait *, a nie * *, a tokeny anulowania są bardziej niezręczne w tym scenariuszu. –

6

Szorstka C# równoważne bez zewnętrznych bibliotek byłoby:

// 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); 
} 

Należy pamiętać, że zwykle najlepiej jest używać urządzenia await/async na jak najwyższym poziomie. Uzyskiwanie dostępu do Result z Task lub używanie Wait może w niektórych przypadkach być introduce deadlocks.