Весь представленный код я загрузил в виде запроса LinqPad, поэтому вы можете попробовать его прямо сейчас. .
В функциональном программировании есть концепция монады (незнакомым с C# программистам я настоятельно рекомендую начать с предоставленной ссылки). Задача C# может считаться монадой, и насколько я понимаю, это именно то, что Вам нужно.
Для целей этого ответа я сделал упрощенный пример того, что у вас есть:
await (await (await A.GetNumber()).DoubleIt()).SquareIt()
где методы следующие (определены как статические только для моего удобства):
public static class A
{
public static Task<int> GetNumber(){return Task.FromResult(3);}
public static Task<int> DoubleIt(this int input){return Task.FromResult(2 * input);}
public static Task<int> SquareIt(this int input){return Task.FromResult(input * input);}
}
Теперь вы можете легко связать их с помощью небольшого количества клея, который может выглядеть так:
public static async Task<TOut> AndThen<TIn, TOut>(this Task<TIn> inputTask, Func<TIn, Task<TOut>> mapping)
{
var input = await inputTask;
return (await mapping(input));
}
Метод AndThen
действует точно так же, как монадическая привязка:
await
A.GetNumber()
.AndThen(A.DoubleIt)
.AndThen(A.SquareIt)
Что еще более важно, C# имеет удобный синтаксис для работы с монадами: синтаксис обработки запросов LINQ. Вам просто нужно определить метод SelectMany, который работает с желаемым типом (в данном случае Task), и вы готовы к работе.
Ниже я реализовал наиболее «хардкорную» перегрузку SelectMany (с дополнительными resultSelector
), которая дает Вам наибольшую гибкость. Простая версия будет почти такой же, как AndThen
(думаю, простое переименование сработает).
public static async Task<TOut> SelectMany<TIn, TInterm, TOut>(
this Task<TIn> inputTask,
Func<TIn, Task<TInterm>> mapping,
Func<TIn, TInterm, TOut> resultSelector)
{
var input = await inputTask;
return resultSelector(input, await mapping(input));
}
С ним Вы можете использовать синтаксис:
var task =
from num in A.GetNumber()
from doubled in num.DoubleIt()
from squared in num.SquareIt()
select $"number: {num} doubled: {doubled}, squared: {squared}";
Console.WriteLine(await task);
И Вы получаете number: 3 doubled: 6, squared: 9
.
Простая версия SelectMany позволит вам использовать squared
как единственное возможное выражение в последней строке select
. Версия "hardcoder" позволяет Вам использовать любое выражение, которое использует любое из значений, определенных после ключевого слова from
.
person
Grzegorz Sławecki
schedule
10.10.2018
Task<Whatever>
в качестве своего первого члена. - person Panagiotis Kanavos   schedule 10.10.2018Historize( this Task<ApplicationProcess>
process,...)`, чтобы разрешить прямую цепочку. Однако каждый такой метод должен использоватьawait process
для получения фактического объекта процесса. Что вы ожидаете получить, объединяя такие методы? Что делаетfn
, зависит ли это отprocess
? Если вы хотите создать конвейеры шагов обработки, используйте библиотеку Dataflow. - person Panagiotis Kanavos   schedule 10.10.2018