这是我能想到的最好的:
public static async IAsyncEnumerable<T> AsAsyncEnumerable<T>(this IEnumerable<Task<T>> tasks)
{
foreach (Task<T> task in tasks)
{
yield return await task;
}
}
有更好/推荐的方法吗?
有更好/推荐的方法吗?
其实不然。您的实施几乎已经尽善尽美了。您可以考虑添加取消支持,如下所示:
public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(
this IEnumerable<Task<T>> source,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(source);
foreach (Task<T> task in tasks)
{
yield return await task.ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
}
}
但这并不是真正需要的。如果消费者想要取消枚举,他们可以使用
await foreach
或 break
退出消费 return
循环。如果 CancellationToken
会影响等待的任务,那么它会很有用,但任务的创建被委托给源 IEnumerable<Task<T>>
,它超出了 ToAsyncEnumerable
方法的边界。因此,我宁愿跳过中间 IEnumerable<Task<T>>
的创建,并将底层 IEnumerable<TSource>
直接投影到 IAsyncEnumerable<TResult>
:
public static async IAsyncEnumerable<TResult> SelectAsync<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, CancellationToken, ValueTask<TResult>> selector,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(selector);
foreach (TSource item in source)
{
yield return await selector(item, cancellationToken).ConfigureAwait(false);
}
}
使用示例:
IAsyncEnumerable<Response> responses = requests
.SelectAsync(async (request, ct) => await Get(request, ct));
await foreach (Response response in responses.WithCancellation(cancellationToken))
{
//...
}