select from linq statement with await

Viewed 101

This seems like it should be very simple, I have the following code

var additionalInformation=   response.AdditionalInformation.Select( async x =>  new AdditionalInformationItem
                {
                    StatementCode = x?.StatementCode?.Value,
                    LimitDateTime = x?.LimitDateTime?.Item?.Value,
                    StatementTypeCode = x?.StatementTypeCode?.Value,
                    StatementDescription = x?.StatementDescription?.Value,
                    AdditionalInformationResult = await BuildAdditionalInformationPointers(x)


                }).ToList();

What I am trying to achieve is for additionalInformation to be of type

List<AdditionalInformationItem>

, what I am getting is List<Task<AdditionalInformationItem>>

Can anyone help me correctly reformulate my statement?

3 Answers

You need to unwrap the tasks using, await Task.WhenAll(additionalInformation) then you access the actual result using additionalInformation[0].Result.

So something like this:

var additionalInformation=   response.AdditionalInformation.Select( async x =>  new AdditionalInformationItem
                {
                    StatementCode = x?.StatementCode?.Value,
                    LimitDateTime = x?.LimitDateTime?.Item?.Value,
                    StatementTypeCode = x?.StatementTypeCode?.Value,
                    StatementDescription = x?.StatementDescription?.Value,
                    AdditionalInformationResult = await BuildAdditionalInformationPointers(x)


                });

await Task.WhenAll(additionalInformation);
//This will iterate the results so may not be the most efficient method if you have a lot of results
List<AdditionalInformationItem> unwrapped = additionalInformation.Select(s => s.Result).ToList();

There is actually no way to do this in a simple lambda expression. The async lambda expression will always return a Task<T>. So you can go quick and dirty and call .Result on the Task (don't do it! Except if you await first as in Liam's answer), or simply initialize a new list and add items in a foreach loop:

var additionalInformation = new List<AdditionalInformationItem>();
foreach (var x in response.AdditionalInformation)
{
    var item = new AdditionalInformationItem
        {
            StatementCode = x?.StatementCode?.Value,
            LimitDateTime = x?.LimitDateTime?.Item?.Value,
            StatementTypeCode = x?.StatementTypeCode?.Value,
            StatementDescription = x?.StatementDescription?.Value,
            AdditionalInformationResult = await BuildAdditionalInformationPointers(x)
        };

    additionalInformation.Add(item);
}

await Task.WhenAll will automatically unwrap the tasks, and will hand you an array with the results.

AdditionalInformationItem[] additionalInformation = await Task.WhenAll(
    response.AdditionalInformation.Select(async x => new AdditionalInformationItem
    {
        StatementCode = x?.StatementCode?.Value,
        LimitDateTime = x?.LimitDateTime?.Item?.Value,
        StatementTypeCode = x?.StatementTypeCode?.Value,
        StatementDescription = x?.StatementDescription?.Value,
        AdditionalInformationResult = await BuildAdditionalInformationPointers(x)
    });
);
Related