2016-08-17 25 views
30

在斯卡拉有一個Promise類,可以用來手動完成一個Future。我正在尋找在C#中的替代品。在C中的等價承諾#

我寫一個測試,我希望它看起來就與此類似:

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

我明白,這可能是不適合C#正確的模式,但我無法找出一個合理的方式即使有些不同的模式也能達到同樣的效果。

編輯:請注意,async/await沒有幫助,因爲我沒有任務等待!我只能訪問將在另一個線程上運行的處理程序。

+0

的可能的複製[如何以及何時使用\'異步\'和\'\伺機'](http://stackoverflow.com/questions/14455293 /如何及何時使用異步和等待) – Stijn

+1

我認爲你正在尋找'任務'。 –

回答

41

在C#:

  • Task<T>是(爲一個單元返回未來或Task)一個未來。
  • TaskCompletionSource<T>是一個承諾。

所以,你的代碼將轉化爲這樣:

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

「定時異步等待」是一個有點尷尬,但它也是在現實世界中的代碼比較少見。單元測試,我只想做一個普通的異步等待:

var promise = new TaskCompletionSource<MyResult>(); 

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

var myResult = await promise.Task; 

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

有一個更好的方法來實現使用取消令牌的超時。請參閱https://stackoverflow.com/q/23476576/1288449 –

+1

@StevenLiekens:我同意超時通常更好地表示爲取消令牌;但是,對於超時用於取消操作的情況,這是最好的選擇。在這種情況下,我們正在討論取消* wait *,而不是*操作*,並且在這種情況下取​​消令牌更加尷尬。 –

6

粗糙的C#相當於沒有第三方庫將是:

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

請注意,通常最好使用盡可能高的await/async。訪問ResultTask或使用Wait可以在某些情況下introduce deadlocks