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?
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.
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.
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); }));
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With