Skip to content

Commit 0a87943

Browse files
CopilotBillWagner
andcommitted
Add explanation and example for ToList() vs ToArray() in async scenarios
Co-authored-by: BillWagner <[email protected]>
1 parent 7e026f7 commit 0a87943

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

docs/csharp/asynchronous-programming/async-scenarios.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,20 @@ You can write this code more succinctly by using LINQ:
130130

131131
:::code language="csharp" source="snippets/async-scenarios/Program.cs" ID="GetUsersForDatasetByLINQ":::
132132

133-
Although you write less code by using LINQ, exercise caution when mixing LINQ with asynchronous code. LINQ uses deferred (or lazy) execution. Asynchronous calls don't happen immediately as they do in a `foreach` loop, unless you force the generated sequence to iterate with a call to the `.ToList()` or `.ToArray()` method. This example uses the <xref:System.Linq.Enumerable.ToArray%2A?displayProperty=nameWithType> method to perform the query eagerly and store the results in an array. This approach forces the `id => GetUserAsync(id)` statement to run and initiate the task.
133+
Here's an example that demonstrates using `ToList()` with `Task.WhenAny` to process tasks as they complete:
134+
135+
:::code language="csharp" source="snippets/async-scenarios/Program.cs" ID="ProcessTasksAsTheyComplete":::
136+
137+
In this example, `ToList()` creates a list that supports the `Remove()` operation, allowing you to dynamically remove completed tasks. This pattern is particularly useful when you want to handle results as soon as they're available, rather than waiting for all tasks to complete.
138+
139+
Although you write less code by using LINQ, exercise caution when mixing LINQ with asynchronous code. LINQ uses deferred (or lazy) execution. Asynchronous calls don't happen immediately as they do in a `foreach` loop, unless you force the generated sequence to iterate with a call to the `.ToList()` or `.ToArray()` method.
140+
141+
You can choose between <xref:System.Linq.Enumerable.ToArray%2A?displayProperty=nameWithType> and <xref:System.Linq.Enumerable.ToList%2A?displayProperty=nameWithType> based on your scenario:
142+
143+
- **Use `ToArray()`** when you plan to process all tasks together, such as with `Task.WhenAll`. Arrays are efficient for scenarios where the collection size is fixed.
144+
- **Use `ToList()`** when you need to dynamically manage tasks, such as with `Task.WhenAny` where you might remove completed tasks from the collection as they finish.
145+
146+
This example uses the `ToArray()` method to perform the query eagerly and store the results in an array. This approach forces the `id => GetUserAsync(id)` statement to run and initiate the task.
134147

135148
## Review considerations for asynchronous programming
136149

docs/csharp/asynchronous-programming/snippets/async-scenarios/Program.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,22 @@ private static async Task<User[]> GetUsersAsyncByLINQ(IEnumerable<int> userIds)
145145
}
146146
// </GetUsersForDatasetByLINQ>
147147

148+
// <ProcessTasksAsTheyComplete>
149+
private static async Task ProcessTasksAsTheyCompleteAsync(IEnumerable<int> userIds)
150+
{
151+
var getUserTasks = userIds.Select(id => GetUserAsync(id)).ToList();
152+
153+
while (getUserTasks.Count > 0)
154+
{
155+
Task<User> completedTask = await Task.WhenAny(getUserTasks);
156+
getUserTasks.Remove(completedTask);
157+
158+
User user = await completedTask;
159+
Console.WriteLine($"Processed user {user.id}");
160+
}
161+
}
162+
// </ProcessTasksAsTheyComplete>
163+
148164
// <ExtractDataFromNetwork>
149165
[HttpGet, Route("DotNetCount")]
150166
static public async Task<int> GetDotNetCountAsync(string URL)
@@ -178,6 +194,9 @@ static async Task Main()
178194
Console.WriteLine($"{user.id}: isEnabled={user.isEnabled}");
179195
}
180196

197+
Console.WriteLine("Processing tasks as they complete...");
198+
await ProcessTasksAsTheyCompleteAsync(ids);
199+
181200
Console.WriteLine("Application ending.");
182201
}
183202
}

0 commit comments

Comments
 (0)