如何与SelectMany一起使用async lambda?

时间:2022-07-20 19:03:11

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

尝试在IEnumerable.SelectMany中使用异步lambda时出现以下错误:

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

无法从使用中推断出方法'IEnumerable System.Linq.Enumerable.SelectMany(此IEnumerable,Func>)'的类型参数。尝试显式指定类型参数

Where GetDataAsync is defined as:

其中GetDataAsync定义为:

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?

我想因为我的GetDataAsync方法实际上返回一个Task >。但为什么选择工作,肯定它应该抛出相同的错误?

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

Is there any way around this?

有没有办法解决?

3 个解决方案

#1


10  

async lambda expression cannot be converted to simple Func<TSource, TResult>.

async lambda表达式无法转换为简单的Func ,tresult>

So, select many cannot be used. You can run in synchronized context:

所以,选择很多都不能使用。您可以在同步上下文中运行:

myEnumerable.Select(c => Functions.GetDataAsync(c.Id)).SelectMany(task => task.Result);

or

要么

List<DataItem> result = new List<DataItem>();

foreach (var ele in myEnumerable)
{
    result.AddRange(await Functions.GetDataAsyncDo(ele.Id));
}

You cannot neither use yield return - it is by design. f.e.:

你不能既不使用收益率 - 它是设计的。 f.e:

public async Task<IEnuemrable<DataItem>> Do() 
{
    ...
    foreach (var ele in await Functions.GetDataAsyncDo(ele.Id)) 
    {
        yield return ele; // compile time error, async method 
                          // cannot be used with yield return
    }

}

#2


21  

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.

说明:您有一个任务列表,每个任务都返回Task >。所以你需要解雇所有,然后等待所有,然后通过SelectMany压缩结果。

#3


2  

Select works because it will return an IEnumerable<Task<T>>, which can then be awaited with e.g. Task.WhenAll.

选择有效,因为它将返回IEnumerable >,然后可以等待,例如Task.WhenAll。

So, an easy workaround to this problem is:

因此,解决此问题的一个简单方法是:

IEnumerable<Task<IEnumerable<T>>> tasks = source.Select(GetNestedEnumerableTask);
IEnumerable<T>[] nestedResults = await Task.WhenAll(tasks);
IEnumerable<T> results = nestedResults.SelectMany(nr => nr);

#1


10  

async lambda expression cannot be converted to simple Func<TSource, TResult>.

async lambda表达式无法转换为简单的Func ,tresult>

So, select many cannot be used. You can run in synchronized context:

所以,选择很多都不能使用。您可以在同步上下文中运行:

myEnumerable.Select(c => Functions.GetDataAsync(c.Id)).SelectMany(task => task.Result);

or

要么

List<DataItem> result = new List<DataItem>();

foreach (var ele in myEnumerable)
{
    result.AddRange(await Functions.GetDataAsyncDo(ele.Id));
}

You cannot neither use yield return - it is by design. f.e.:

你不能既不使用收益率 - 它是设计的。 f.e:

public async Task<IEnuemrable<DataItem>> Do() 
{
    ...
    foreach (var ele in await Functions.GetDataAsyncDo(ele.Id)) 
    {
        yield return ele; // compile time error, async method 
                          // cannot be used with yield return
    }

}

#2


21  

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.

说明:您有一个任务列表,每个任务都返回Task >。所以你需要解雇所有,然后等待所有,然后通过SelectMany压缩结果。

#3


2  

Select works because it will return an IEnumerable<Task<T>>, which can then be awaited with e.g. Task.WhenAll.

选择有效,因为它将返回IEnumerable >,然后可以等待,例如Task.WhenAll。

So, an easy workaround to this problem is:

因此,解决此问题的一个简单方法是:

IEnumerable<Task<IEnumerable<T>>> tasks = source.Select(GetNestedEnumerableTask);
IEnumerable<T>[] nestedResults = await Task.WhenAll(tasks);
IEnumerable<T> results = nestedResults.SelectMany(nr => nr);