Обещающий эквивалент в С#
В 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
здесь не помогает, так как у меня нет задачи, ожидающей! Я просто имею доступ к обработчику, который будет запущен в другом потоке.
Ответы
Ответ 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
может в некоторых случаях ввести тупики.
Ответ 3
Вы можете использовать библиотеку С# Promises
Открыть источник на Github: https://github.com/Real-Serious-Games/C-Sharp-Promise
Доступно на NuGet: https://www.nuget.org/packages/RSG.Promise/
Ответ 4
Попробуйте изучить асинхронную модель. Задачи - ближайший эквивалент в С#.
Здесь ссылка на статью MS, объясняющую их использование.
Ответ 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);
}