C# C:如何将任务转换为任务的IEnumerable

C# C:如何将任务转换为任务的IEnumerable,c#,.net,async-await,C#,.net,Async Await,我有Nito.AsyncEx.AsyncCollection,我想把它包装成类似IAsyncEnumerable的东西 现在我只使用IEnumerable而不是IAsyncEnumerable 我需要像SelectMany这样的东西来平展列表。这就是问题所在。以下代码不起作用 有可能让它工作吗 public static IEnumerable<Task<T>> Flatten<T>(IEnumerable<Task<T[]>> sou

我有Nito.AsyncEx.AsyncCollection,我想把它包装成类似IAsyncEnumerable的东西

现在我只使用IEnumerable而不是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 );
        }
    }
}
像这样使用 定义任务并在其中定义类型并等待结果,确保等待的是异步的。就像下面给出的方法一样

public async Task<IEnumerable<T>> getIEnumerable () {
 return await yourresult.toListAsync();

}

最好的解决方案是等待几个月,直到iSyncEnumerable成为一个真正的东西。下一个最佳解决方案是使用IAsyncEnumerable from。但是现在

IEnumerable是一个同步拉式迭代器。因此,它必须同步提供它的T实例。更重要的是,它必须同步提供实例数

任务是单个项的异步拉取。它将仅异步提供其T实例

问题是:您想要的结果IEnumerable必须能够:

同步提供每个任务。不太难;如果绝对必要,可以使用TaskCompletionSource。 同步提供其计数。换句话说,它需要同步地提供每个任务。都是。考虑到您的输入,这是不可能的。 您的输入是IEnumerable。因为这是IEnumerable,所以可以同步获取计数,但这只是任务项的计数,即T[]项的计数。要执行展平操作,您必须等待每个任务项,以获得T项的计数。因此,您不能生成一个IEnumerable,它可以同步地知道它有多少项

您遇到了这种类型限制,因为IEnumerable与IAsyncEnumerable不同

你的选择是:

使用真正的IAsyncEnumerable,由您自己编写或通过System.Interactive.Async编写。优点:正确的类型允许语义精确的代码。缺点:IAsyncEnumerable的生产和消费目前仍是一个难题。 提前完成所有异步工作。优点:代码更简单。缺点:改变你想要的语义。 使用第二个选项,展平操作符可以如下所示:

public static async Task<IEnumerable<T>> Flatten<T>(IEnumerable<Task<T[]>> tasks) 
{
  var results = await Task.WhenAll(tasks);
  return results.SelectMany(x => x);
}

在得到一个真正的IAsyncEnumerable之前,许多运算符将要求将来的任务以这样的方式结束。

您能描述一下不工作吗?我在迭代器中使用wait方法。