我正在修补IAsyncEnumerable
C#8.0中的新内容。假设我有一些我想使用的方法:
public IAsyncEnumerableSomeBlackBoxFunctionAsync (...) { ... }
我知道我可以将其与await foreach...
语法一起使用。但是,可以说,我的使用者需要从该功能中获得所有结果,然后才能继续。在继续之前等待所有结果的最佳语法是什么?换句话说,我希望能够执行以下操作:
// but that extension - AllResultsAsync() - doesn't exist :-/ ListmyList = await SomeBlackBoxFunctionAsync ().AllResultsAsync();
正确的方法是什么?
首先发出警告:按照定义,异步流可能永远不会结束,并且会继续产生结果,直到应用程序终止。这已经在SignalR或gRPC中使用。轮询循环也以这种方式工作。
使用ToListAsync
上的异步流可能产生意想不到的后果。
这样的操作员已经可以通过System.Linq.Async包获得。
通过ToListAsync可以使用整个流。该代码*看似简单,但隐藏了一些有趣的问题:
public static ValueTask> ToListAsync
(this IAsyncEnumerable source, CancellationToken cancellationToken = default) { if (source == null) throw Error.ArgumentNull(nameof(source)); if (source is IAsyncIListProvider listProvider) return listProvider.ToListAsync(cancellationToken); return Core(source, cancellationToken); static async ValueTask > Core(IAsyncEnumerable
source, CancellationToken cancellationToken) { var list = new List (); await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false)) { list.Add(item); } return list; } }
首先,它返回一个ValueTask
。其次,它确保观察到并ConfigureAwait(false)
使用取消,以防止死锁。最后,如果源已经提供了自己的ToListAsync
实现,则操作员将遵循该实现。