Skip to content

Clarify expected behavior in LINQ async example #27720

Open
@soooch

Description

@soooch

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions