Await Tuples Directly

Mehran Davoudi - Nov 3 '23 - - Dev Community

Imagine if you could write code like this:

var task1 = CountAsync();
var task2 = GetMessageAsync();

// How to await tuples directly!?
var (count, message) = await (task1, task2);
// or even this:
var (count, message) = await (CountAsync(), GetMsgAsync());
Enter fullscreen mode Exit fullscreen mode

This would allow you to await multiple asynchronous tasks in a single line of code, without using Task.WhenAll or Task.WhenAny. How cool is that?

Unfortunately, this is not possible in C# as it is. A Tuple is not an awaitable type, and you cannot use the await keyword on it. Does that mean we have to give up on this idea? NO!

We can make it happen by using the power of extension methods.

You may already know that in C#, you can await any object that has a GetAwaiter method that returns a TaskAwaiter. This means that we can add an extension method called GetAwaiter to tuples and make them awaitable.

public static TaskAwaiter<(T1, T2)> GetAwaiter<T1, T2>(this (Task<T1>, Task<T2>) tuple)
{
  async Task<(T1, T2)> UnifyTasks()
  {
    var (task1, task2) = tuple;
    await Task.WhenAll(task1, task2);
    return (task1.Result, task2.Result);
  }

  return UnifyTasks().GetAwaiter();
}
Enter fullscreen mode Exit fullscreen mode

That's it, all done!

Now you can easily await on tuples. To make it available on all types of tuples and enumerables, I've written this library on GitHub.

All you need is to install EasyAsync Nuget package:

Install-Package EasyAsync
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . .