Promesa equivalente en C#


En Scala hay una clase Promise que podría usarse para completar un Futuro manualmente. Estoy buscando una alternativa en C#.

Estoy escribiendo una prueba y quiero que se vea similar a esta:

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

Entiendo que este probablemente no sea el patrón correcto para C#, pero no pude encontrar una manera razonable de lograr lo mismo incluso con un patrón algo diferente.

EDITAR: tenga en cuenta que async/await no ayuda aquí, ya que no tengo una tarea que esperar! Me solo tienes un acceso a un controlador que se ejecutará en otro hilo.

Author: eddyP23, 2016-08-17

4 answers

En C#:

  • Task<T> es un futuro (o Task para un futuro de retorno de unidad).
  • TaskCompletionSource<T> es una promesa.

Así que su código se traduciría como tal:

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

La "espera asincrónica temporizada" es un poco incómoda, pero también es relativamente poco común en código del mundo real. Para las pruebas unitarias, solo haría una espera asíncrona regular:

var promise = new TaskCompletionSource<MyResult>();

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

var myResult = await promise.Task;

Assert.Equals("my header", myResult.Header);
 54
Author: Stephen Cleary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-17 13:47:56

El equivalente aproximado de C# sin bibliotecas de terceros sería:

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

Tenga en cuenta que por lo general es mejor utilizar el await/async a un nivel tan alto como sea posible. Acceder a Result de un Task o usar Wait puede en algunos casos introducir bloqueos.

 8
Author: Dark Falcon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:27

Puede usar la biblioteca de promesas de C#

Código Abierto en Github: https://github.com/Real-Serious-Games/C-Sharp-Promise

Disponible en NuGet: https://www.nuget.org/packages/RSG.Promise/

 5
Author: Mathew Sachin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-17 12:31:53

Intente buscar en el modelo asincrónico. Las tareas son el equivalente más cercano en c#.

Aquí hay un enlace a un artículo de MS explicando su uso.

 2
Author: Rich Linnell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-17 12:27:36