Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use async lambda with SelectMany?

I'm getting the following error when trying to use an async lambda within IEnumerable.SelectMany:

var result = myEnumerable.SelectMany(async (c) => await Functions.GetDataAsync(c.Id)); 

The type arguments for method 'IEnumerable System.Linq.Enumerable.SelectMany(this IEnumerable, Func>)' cannot be inferred from the usage. Try specifying the type arguments explicitly

Where GetDataAsync is defined as:

public interface IFunctions {     Task<IEnumerable<DataItem>> GetDataAsync(string itemId); }  public class Functions : IFunctions {     public async Task<IEnumerable<DataItem>> GetDataAsync(string itemId) {         // return await httpCall();     } } 

I guess because my GetDataAsync method actually returns a Task<IEnumerable<T>>. But why does Select work, surely it should throw the same error?

var result = myEnumerable.Select(async (c) => await Functions.GetDataAsync(c.Id)); 

Is there any way around this?

like image 547
CodingIntrigue Avatar asked Nov 03 '15 09:11

CodingIntrigue


People also ask

Why can't I use select many in async lambda expression?

async lambda expression cannot be converted to simple Func<TSource, TResult>. So, select many cannot be used. You can run in synchronized context: Show activity on this post. Select works because it will return an IEnumerable<Task<T>>, which can then be awaited with e.g. Task.WhenAll.

What is selectmany in lambda?

SelectMany: Flattens collections into a single collection (similar to cross join in SQL). SelectMany: Flattens collections into a single collection (similar to cross join in SQL). This Lambda Expression sample cross joins two arrays, and gets cartesian product. This Lambda Expression sample cross joins two arrays, and gets cartesian product.

How do I Mark a Lambda as async in SQLite?

To mark a lambda async, simply prepend async before its argument list: // Add a command to delete the current Group contextMenu.Commands.Add (new UICommand ("Delete this Group", async (contextMenuCmd) => { SQLiteUtils slu = new SQLiteUtils (); await slu.DeleteGroupAsync (groupName); }));

What is the use of selectmany in LINQ?

The SelectMany in LINQ is used to project each element of a sequence to an IEnumerable<T> and then flatten the resulting sequences into one sequence. That means the SelectMany operator combines the records from a sequence of results and then converts it into one result.


Video Answer


1 Answers

This is an extension:

public static async Task<IEnumerable<T1>> SelectManyAsync<T, T1>(this IEnumerable<T> enumeration, Func<T, Task<IEnumerable<T1>>> func) {     return (await Task.WhenAll(enumeration.Select(func))).SelectMany(s => s); } 

That allows you to run:

var result = await myEnumerable.SelectManyAsync(c => Functions.GetDataAsync(c.Id)); 

Explanation: you have a list of tasks, each returns Task<IEnumerable<T>>. So you need to fire them all, then await all, and then squash the result via SelectMany.

like image 91
SergeyGrudskiy Avatar answered Oct 16 '22 21:10

SergeyGrudskiy