Продолжение задачи <T> для задачи <U> без блокировки результата
У меня есть два асинхронных метода Task<int> DoInt()
и Task<string> DoString(int value)
. У меня есть третий асинхронный метод Task<string> DoBoth(int value)
, целью которого является асинхронное выполнение DoInt()
, выводящий его на DoString(int)
, и результат будет результатом DoBoth()
.
Важными ограничениями являются:
- Возможно, у меня нет исходного кода для
DoInt()
или DoString()
, поэтому я не могу
измените их.
- Я не хочу блокировать в любой момент
- Результат (результат) одной задачи должен быть передан в качестве входных данных для следующего
- Конечный результат (результат) - это то, что я хочу быть результатом
DoBoth()
Ключом у меня уже есть методы, которые являются асинхронными (т.е. return Task), и я хочу передать данные из задачи в задачу без блокировки по пути, возвращая конечный результат в исходную задачу. Я могу сделать все следующее, кроме как блокирование в следующем коде:
Пример кода:
// Two asynchronous methods from another library, i.e. can't be changed
Task<int> DoInt();
Task<string> DoString(int value);
Task<string> DoBoth()
{
return DoInt().ContinueWith<string>(intTask =>
{
// Don't want to block here on DoString().Result
return DoString(intTask.Result).Result;
});
}
Так как Task<string> DoString(int)
уже является асинхронным методом, как я могу создать для него неблокирующее продолжение? Фактически я хочу создать продолжение из существующей задачи, а не из Func.
Ответы
Ответ 1
Вы можете написать всю цепочку, используя TaskExtensions.Unwrap как:
Task<string> DoBoth(int value)
{
Task<Task<string>> task = DoInt(value).ContinueWith(valueTask =>
{
return DoString(valueTask.Result);
});
return task.Unwrap();
}
Обратите внимание, что это предполагает, что DoInt
определяется как Task<int> DoInt(int value);
, который отличается от вашего описания, но следует вашему примеру кода.
Если DoInt не принимает аргумент int (соответствующий вашим объявлениям), это может стать:
Task<string> DoBoth()
{
return DoInt().ContinueWith(t => DoString(t.Result)).Unwrap();
}
В качестве дополнительного - используя С# 5 и .NET 4.5 (или пакет асинхронного таргетинга), вы можете записать это как:
async Task<string> DoBoth(int value)
{
int first = await DoInt(value);
return await DoString(first);
}
Ответ 2
Вам нужно что-то вроде метода flatMap в функциональных языках. http://en.wikipedia.org/wiki/Monad_%28functional_programming%29#fmap_and_join