Promise equivalent in C#
C#PromiseAsync AwaitTaskFutureC# Problem Overview
In Scala there is a Promise class that could be used to complete a Future manually. I am looking for an alternative in C#.
I am writing a test and I want it to look it similar to this:
// 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);
I understand that this is probably not the right pattern for C#, but I couldn't figure out a reasonable way to achieve the same thing even with somewhat different pattern.
EDIT: please note, that async
/await
doesn't help here, as I don't have a Task to await! I just have an access to a handler that will be run on another thread.
C# Solutions
Solution 1 - C#
In C#:
Task<T>
is a future (orTask
for a unit-returning future).TaskCompletionSource<T>
is a promise.
So your code would translate as such:
// 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);
The "timed asynchronous wait" is a bit awkward, but it's also relatively uncommon in real-world code. For unit tests, I would just do a regular asynchronous wait:
var promise = new TaskCompletionSource<MyResult>();
handlerMyEventsWithHandler(msg => promise.TrySetResult(msg));
var myResult = await promise.Task;
Assert.Equals("my header", myResult.Header);
Solution 2 - C#
The rough C# equivalent without third-party libraries would be:
// 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);
}
Note that it is usually best to use the await
/async
to as high a level as possible. Accessing the Result
of a Task
or using Wait
can in some cases introduce deadlocks.
Solution 3 - C#
You can use C# Promises library
Open sourced on Github: https://github.com/Real-Serious-Games/C-Sharp-Promise
Available on NuGet: https://www.nuget.org/packages/RSG.Promise/
Solution 4 - C#
This is the old school way of doing Promises.
Back then i believe it was called synchronization :)
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);
Just for Completeness - to large for a comment.
I agree with Stephen Cleary's answer.
But if you are building a facade around some legacy code this can be used to wrap old API's in a Task like:
public Task<MyResult> GetResultAsync() {
MyResult result = null;
var are = new AutoResetEvent(false);
handlerMyEventsWithHandler(msg => {
result = msg;
are.Set();
});
are.WaitOne();
return Task.FromResult(result);
}
Solution 5 - C#
Try looking into the async model. Tasks are the nearest equivalent in c#.
Solution 6 - C#
You can download future(https://www.nuget.org/packages/Future/) package from Nuget and can be used as below
Promise<int> promise = new Promise<int>();
new Task(() =>
{
Thread.Sleep(100);
promise.Set(20);
}).Start();
int result=promise.Get();
As per the example you can create a promise object and do a get to get result, get will wait until result is on the object. You do a set from another thread as show in the above example.
This package provides the below two classes
-
Promise : Which waits indefinitely for the result
-
TimedPromise : Which waits for the result only till the specified time. If result is not available with in the time, it throws timeout exception