我有Nito.AsyncEx.AsyncCollection<MyItem[]>
,我想将其包装成类似IAsyncEnumerable<MyItem>
的东西。
目前,我仅使用IEnumerable<Task<T>>
而不是IAsyncEnumerable
。
我需要像SelectMany
这样的东西来平整列表。这就是问题。以下代码不起作用。
能否使其正常工作?
public static IEnumerable<Task<T>> Flatten<T>(IEnumerable<Task<T[]>> source) {
foreach (Task<T[]> task in source) {
// We should convert Task<T[]> to IEnumerable of Task<T>
T[] result = await task;
foreach (T item in result) {
yield return Task.FromResult( item );
}
}
}
答案 0 :(得分:1)
最好的解决方案是等待几个月,直到IAsyncEnumerable<T>
成为现实。第二好的解决方案是使用System.Interactive.Async中的IAsyncEnumerable<T>
。但是现在...
IEnumerable<T>
是同步拉式迭代器。因此,它必须同步提供其T
实例。对于这个问题,更重要的是,它必须同步提供实例的 count 。
Task<T>
是单个项目的异步提取。它将仅异步提供其T
实例。
这就是问题所在:您想要的结果IEnumerable<Task<T>>
必须能够:
Task<T>
。不是太难;您可以在绝对必要的情况下使用TaskCompletionSource<T>
。Task<T>
。他们全部。根据您的输入,这是不可能的。您的输入是IEnumerable<Task<T[]>>
。由于这是IEnumerable<>
,因此您可以同步获取计数,但这只是Task<T[]>
项的计数-即T[]
项的计数。要进行展平操作,您必须await
个Task<T[]>
中的每一个,以获得T
个项目的计数。因此,您无法生成可以同步知道其有多少项的IEnumerable<Task<T>>
。
由于IEnumerable<Task<T>>
与IAsyncEnumerable<T>
不同,因此您遇到了这种类型限制。
您的选择是:
IAsyncEnumerable<T>
,自己编写或通过System.Interactive.Async编写。优点:适当的类型允许语义上精确的代码。缺点:IAsyncEnumerable<T>
的生产和消费仍然很痛苦(目前)。使用第二个选项,您的展平运算符可能看起来像这样:
public static async Task<IEnumerable<T>> Flatten<T>(IEnumerable<Task<T[]>> tasks)
{
var results = await Task.WhenAll(tasks);
return results.SelectMany(x => x);
}
在您拥有真实的IAsyncEnumerable<T>
之前,许多运营商将要求未来(Task<T>
)像这样最终出现在外部。
答案 1 :(得分:-1)
像这样使用 定义Task并在其中定义您的类型并等待结果,确保您正在等待的是异步的。就像下面给出的方法一样。
public async Task<IEnumerable<T>> getIEnumerable () {
return await yourresult.toListAsync();
}