Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't an async LINQ Select lambda require a return value

I am reading Concurrency in C# by Stephen Cleary in which there is an example that has puzzled me for a while.

Normally the LINQ Select method requires a lambda method that returns the value for the result collection.

In the book on page 30 there is an example where the lambda doesn't return anything, but nevertheless, the code compiles and runs fine:

static async Task<int> DelayAndReturnAsync(int val)
{
   await Task.Delay(TimeSpan.FromSeconds(val));
   return val;
}

static async Task ProcessTasksAsync()
{
   // Create a sequence of tasks
   Task<int> taskA = DelayAndReturnAsync(2);
   Task<int> taskB = DelayAndReturnAsync(3);
   Task<int> taskC = DelayAndReturnAsync(1);

   var tasks = new[] { taskA, taskB, taskC };

   var processingTasks = tasks.Select(async t => 
   {
      var result = await t;
      Trace.WriteLine(result);
      // Note: nothing is returned
   }).ToArray();

   // Await all processing to complete
   await Task.WhenAll(processingTasks);
}

// Outputs:
// 1
// 2
// 3

The question is about this part:

var processingTasks = tasks.Select(async t => 
   {
      var result = await t;
      Trace.WriteLine(result);
      // Note: nothing is returned
   }).ToArray();

Why is this? Is it a recommended approach?

UPDATE:

Where is this behaviour documented?

like image 621
teisnet Avatar asked Feb 26 '19 16:02

teisnet


1 Answers

It's just like writing an async method that doesn't return a value, but uses a Task to indicate completion:

public async Task FooAsync()
{
    Console.WriteLine("Before");
    await Task.Delay(1000);
    Console.WriteLine("After");
}

As an async anonymous function, that would be:

Func<Task> foo = async () =>
{
    Console.WriteLine("Before");
    await Task.Delay(1000);
    Console.WriteLine("After");
};
like image 172
Jon Skeet Avatar answered Oct 01 '22 03:10

Jon Skeet