The functional programming era LinqToTask

Back in 2007, Microsoft introduced linq in 3 flavors (LinqToSql, LinqToXml, and LinqToObjects), asynchronous programming was not that popular at this time.
In the current time, most of the c# programming relay on “async Task<T>” to support asynchronous programming. While asynchronous programming helped a lot of developers to create highly responsive applications this came with a cost.
Imagine that you have an async method that returns an enumerable of Task<int>
IEnumerable<Task<int>> GenerateRandomNumbers(int count)
{ var rand=new Random(); for (int i = 0; i < count; i++) { yield return Task.Run(() => rand.Next()); }}
and now you wanna sum the results of GenerateRandomNumber(3), most probably you will end up with something ugly like this where you use the not recommended Task.Result
GenerateRandomNumbers(3).Sum( task => task.Result);or
var result = 0;foreach (var generateRandomNumber in GenerateRandomNumbers(3)){result += await generateRandomNumber;}Console.WriteLine(result);
LinqToTask
the power of linq c# is that it is extendable, most of the c sharp developers think that Select and SelectMany can only be used with IEnumerable but that is not true, you can use them with any type you want, just start by defining them as extension methods to the target type which is Task.
As it is obvious the Select method awaits for the task result and passes it to the selector function while the SelectMany method does the same and await for the results.
now we can get the sum of our 3 generated random numbers using
var aggregation=GenerateRandomNumbers(3).Aggregate((task, task1) => task.SelectMany(async x => x + await task1));Console.WriteLine(await aggregation);
and we can do any transformation we want on our Tasks using the select method for example
Console.WriteLine(await Task.FromResult(2).Select(i => i + 1)); //return 3or
Console.WriteLine( await Task.FromResult(2).Select(i => i.ToString()));//return "2"
