How to convert Dictionarystring, Taskint to TaskDictionarystring, int
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
If you have a Dictionary<string, Task<int>>, you already have the keys and you already have asynchronous computations for the values. What you need is a single task that waits for all those value tasks and then rebuilds a dictionary of completed results. The standard tool for that is Task.WhenAll.
The Shape of the Problem
The input type means:
- each key is already known
- each value task will eventually produce an
int - the tasks may already be running
The output type, Task<Dictionary<string, int>>, means one asynchronous operation that completes only when all per-key tasks have completed.
Use Task.WhenAll Over Projected Key-Value Tasks
A clean solution is to project each dictionary entry into a task that returns a completed key-value pair, then await all of them together.
This preserves the original keys and awaits all value tasks concurrently.
Why Task.WhenAll Is the Right Tool
Task.WhenAll does not run the tasks by itself. It creates a new task that completes when all supplied tasks complete. That distinction matters.
If the dictionary's Task<int> values are already in progress, WhenAll simply coordinates them. If they have not started yet because they came from lazy factories, then the task creation logic has to happen earlier.
Avoid Awaiting Sequentially in a Loop
This is a common but weaker pattern.
It works, but it awaits entry by entry. If the tasks are not already all in progress, this can serialize the work. Even when they are already running, it expresses the intent less clearly than Task.WhenAll.
Handle Exceptions Deliberately
If one or more inner tasks fail, the returned task from Task.WhenAll also fails. That is usually what you want because the aggregate result is incomplete.
If partial success matters, you need a different design, such as wrapping each task result in a success-or-error object rather than allowing exceptions to abort the whole aggregate.
Cancellation Works the Same Way
If one of the inner tasks is canceled, the aggregate task reflects cancellation behavior as well. The exact result depends on whether other tasks faulted or completed. The important point is that Task.WhenAll preserves the semantics of the underlying asynchronous operations rather than hiding them.
Keep the Input Immutable During Aggregation
Do not mutate the dictionary while you are projecting and awaiting its tasks. If the collection changes during enumeration, you can get runtime errors or inconsistent results.
A simple rule is to treat the input dictionary as fixed for the duration of aggregation.
Common Pitfalls
- Awaiting each dictionary task sequentially instead of aggregating them.
- Assuming
Task.WhenAllstarts tasks that have not actually been created yet. - Forgetting that one faulted inner task faults the aggregate operation.
- Mutating the dictionary while enumerating it.
- Rebuilding the result with logic that accidentally loses keys or duplicates them.
Summary
- Convert the dictionary by awaiting all value tasks and then rebuilding the completed key-value pairs.
- '
Task.WhenAllis the standard way to aggregate the asynchronous work.' - Project each entry into a task that returns a completed
KeyValuePair<string, int>. - Be explicit about exception and cancellation behavior.
- Treat the input dictionary as stable while the aggregation is running.

