Skip to content

Commit bf6134c

Browse files
CopilotBillWagnergewarren
authored
Clarify expected behavior in LINQ async example (#47626)
* Initial plan * Clarify LINQ async example behavior and add contrasting examples Co-authored-by: BillWagner <[email protected]> * Fix markdown lint issues: remove trailing spaces and add blank lines around code blocks Co-authored-by: BillWagner <[email protected]> * Apply reviewer suggestions: fix punctuation and use xrefs for API links Co-authored-by: gewarren <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: BillWagner <[email protected]> Co-authored-by: gewarren <[email protected]>
1 parent 19e3528 commit bf6134c

File tree

1 file changed

+21
-1
lines changed

1 file changed

+21
-1
lines changed

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,27 @@ 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+
Although you write less code by using LINQ, exercise caution when mixing LINQ with asynchronous code. LINQ uses deferred (or lazy) execution, which means that without immediate evaluation, async calls don't happen until the sequence is enumerated.
134+
135+
The previous example is correct and safe, because it uses the <xref:System.Linq.Enumerable.ToArray%2A?displayProperty=nameWithType> method to immediately evaluate the LINQ query and store the tasks in an array. This approach ensures the `id => GetUserAsync(id)` calls execute immediately and all tasks start concurrently, just like the `foreach` loop approach.
136+
137+
**Problematic approach** (without immediate evaluation):
138+
139+
```csharp
140+
// DON'T do this - tasks won't start until enumerated.
141+
var getUserTasks = userIds.Select(id => GetUserAsync(id)); // No .ToArray()!
142+
return await Task.WhenAll(getUserTasks); // Tasks start here.
143+
```
144+
145+
**Recommended approach**:
146+
147+
```csharp
148+
// DO this - tasks start immediately.
149+
var getUserTasks = userIds.Select(id => GetUserAsync(id)).ToArray();
150+
return await Task.WhenAll(getUserTasks);
151+
```
152+
153+
Always use <xref:System.Linq.Enumerable.ToArray%2A?displayProperty=nameWithType> or <xref:System.Linq.Enumerable.ToList%2A?displayProperty=nameWithType> when creating tasks with LINQ to ensure immediate execution and concurrent task execution.
134154

135155
## Review considerations for asynchronous programming
136156

0 commit comments

Comments
 (0)