2016-08-17 22 views
30

Trong Scala có một lớp Promise có thể được sử dụng để hoàn thành một tương lai bằng tay. Tôi đang tìm kiếm một thay thế trong C#.Promise tương đương trong C#

Tôi viết một bài kiểm tra và tôi muốn nó trông nó tương tự như sau:

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

Tôi hiểu rằng điều này có lẽ không phải là mô hình phù hợp với C#, nhưng tôi không thể tìm ra một cách hợp lý để đạt được điều tương tự ngay cả với mô hình hơi khác.

CHỈNH SỬA: xin lưu ý rằng async/await không giúp ích gì ở đây vì tôi không có Nhiệm vụ để chờ đợi! Tôi chỉ có quyền truy cập vào trình xử lý sẽ chạy trên một chuỗi khác.

+0

Có thể sao chép [cách và thời điểm sử dụng \ 'async \ 'và \' await \'] (http://stackoverflow.com/questions/14455293/how-and-when-to-use-async-and-await) – Stijn

+1

Tôi nghĩ bạn đang tìm kiếm 'Task '. –

Trả lời

41

Trong C#:

  • Task<T> là một tương lai (hoặc Task cho một tương lai đơn vị trở lại).
  • TaskCompletionSource<T> là lời hứa.

Vì vậy, mã của bạn sẽ dịch như vậy:

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

Các "theo thời gian chờ đợi không đồng bộ" là một chút vụng về, nhưng nó cũng tương đối phổ biến trong mã thực tế. Đối với các bài kiểm tra đơn vị, tôi sẽ chỉ thực hiện chờ đợi không đồng bộ thông thường:

var promise = new TaskCompletionSource<MyResult>(); 

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

var myResult = await promise.Task; 

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

Có một cách hay hơn để triển khai thời gian chờ bằng cách sử dụng mã thông báo hủy. Xem https://stackoverflow.com/q/23476576/1288449 –

+1

@StevenLiekens: Tôi đồng ý rằng thời gian chờ thường được biểu thị tốt hơn dưới dạng mã thông báo hủy; tuy nhiên, đó là tốt nhất cho các tình huống mà thời gian chờ được sử dụng để hủy bỏ một hoạt động. Trong trường hợp này, chúng ta đang nói về việc hủy bỏ * chờ *, không phải thao tác *, và các mã thông báo hủy bỏ sẽ khó xử hơn trong trường hợp này. –

6

Các thô C# tương đương mà không thư viện của bên thứ ba sẽ là:

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

Lưu ý rằng tốt nhất nên sử dụng các mức await/async đến mức cao nhất có thể. Truy cập vào Result trong số Task hoặc sử dụng Wait có thể trong một số trường hợp introduce deadlocks.