Подтвердить что ты не робот

Обещающий эквивалент в С#

В Scala существует класс Promise, который может быть использован для завершения Будущего вручную. Я ищу альтернативу в С#.

Я пишу тест, и я хочу, чтобы он выглядел примерно так:

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

Я понимаю, что это, вероятно, не правильный шаблон для С#, но я не мог найти разумный способ добиться того же самого даже с несколько иным шаблоном.

РЕДАКТИРОВАТЬ: обратите внимание, что async/await здесь не помогает, так как у меня нет задачи, ожидающей! Я просто имею доступ к обработчику, который будет запущен в другом потоке.

4b9b3361

Ответ 1

В С#:

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

Ответ 2

Грубый эквивалент С# без сторонних библиотек:

// 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 как можно более высокий уровень. Доступ к Result для Task или с помощью Wait может в некоторых случаях ввести тупики.

Ответ 5

Это старый способ выполнения Обещаний.
Тогда я считаю, что это называется синхронизацией :)

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

Просто для полноты - для большого комментария.
Я согласен со Стивеном Клири ответом.

Но если вы строите фасад вокруг какого-то унаследованного кода, это можно использовать, чтобы обернуть старый API в задачу вроде:

public Task<MyResult> GetResultAsync() {
    MyResult result = null;
    var are = new AutoResetEvent(false);
    handlerMyEventsWithHandler(msg => {
        result = msg;
        are.Set();
    });
    are.WaitOne();
    return Task.FromResult(result);
}