Await multiple tasks with different return types — elegantly.
TaskTupleAwaiter lets you await a tuple of tasks and destructure the results in a single line. No more juggling Task.WhenAll, casting from object, or writing verbose boilerplate to run independent async operations in parallel.
// ❌ Without TaskTupleAwaiter
var userTask = GetUserAsync(id);
var ordersTask = GetOrdersAsync(id);
await Task.WhenAll(userTask, ordersTask);
var user = userTask.Result;
var orders = ordersTask.Result;
// ✅ With TaskTupleAwaiter
var (user, orders) = await (GetUserAsync(id), GetOrdersAsync(id));- Tuple-based
await— fire multiple async calls in parallel and destructure results with a singleawait - Supports up to 16 tasks — mix and match any combination of return types
ConfigureAwaitsupport — works withConfigureAwait(false)and .NET 8+ConfigureAwaitOptions- Non-generic
Tasksupport — await tuples ofTask(not justTask<T>) when you don't need return values - Zero dependencies — a single file, no external packages (except
System.ValueTupleon .NET Framework 4.6.2) - Broad compatibility — targets .NET Standard 2.0, .NET Framework 4.6.2, and .NET 8+
dotnet add package TaskTupleAwaiterOr via the NuGet Package Manager:
Install-Package TaskTupleAwaiter
var (name, age) = await (GetNameAsync(), GetAgeAsync());var (policy, preferences) = await (
GetPolicyAsync(policyId, cancellationToken),
GetPreferencesAsync(cancellationToken)
).ConfigureAwait(false);var (user, settings) = await (
GetUserAsync(userId),
GetSettingsAsync()
).ConfigureAwait(ConfigureAwaitOptions.None);var (a, b, c, d, e) = await (
GetAAsync(),
GetBAsync(),
GetCAsync(),
GetDAsync(),
GetEAsync()
);await (SendEmailAsync(), LogAuditAsync(), InvalidateCacheAsync());TaskTupleAwaiter provides extension methods on ValueTuple<Task<T1>, ..., Task<TN>> (and ValueTuple<Task, ..., Task>) that implement the awaitable pattern. Under the hood each awaiter calls Task.WhenAll to run the tasks concurrently, then unwraps the individual results into a tuple — giving you the performance of parallel execution with the ergonomics of simple destructuring.
| Target | Version |
|---|---|
| .NET Standard | 2.0 |
| .NET Framework | 4.6.2+ |
| .NET | 8.0+ |
Based on the original work by Joseph Musser (@jnm2) — original gist.
MIT © Brian Buvinghausen