dotnet / docs

This repository contains .NET Documentation.
https://learn.microsoft.com/dotnet
Creative Commons Attribution 4.0 International
4.21k stars 5.86k forks source link

Clarify expected behavior in LINQ async example #27720

Open soooch opened 2 years ago

soooch commented 2 years ago

This suggestion is in reference to the following section:

Here's another way to write this more succinctly, using LINQ:

public async Task<User> GetUserAsync(int userId)
{
    // Code omitted:
    //
    // Given a user Id {userId}, retrieves a User object corresponding
    // to the entry in the database with {userId} as its Id.
}

public static async Task<User[]> GetUsersAsync(IEnumerable<int> userIds)
{
    var getUserTasks = userIds.Select(id => GetUserAsync(id));
    return await Task.WhenAll(getUserTasks);
}

Although it's less code, use caution when mixing LINQ with asynchronous code. Because LINQ uses deferred (lazy) execution, async calls won't happen immediately as they do in a foreach loop unless you force the generated sequence to iterate with a call to .ToList() or .ToArray().

To me it is very unclear what exactly is meant by the inclusion of this section. Is it an example of what not to do or is it a reasonable way to improve brevity? Will the provided code snippet actually be negatively impacted by laziness? If not, why? Would it be better if the LINQ expression was concluded with a ToList or ToArray, or would that trigger unnecessary allocations?

I understand that the answers vary based on the exact situation, but I would appreciate some more concrete behavior expectations for the given code. I think an explanation of when those expectations should change would also be nice.


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

BillWagner commented 2 years ago

Thanks for raising this issue @soooch

I've added it to our backlog to address in the near future.