我正在逐步将Ix.NET引入一个旧项目中。 我有许多存储级别的API返回Task<IEnumerable<T>>
,但是我想将它们适应于IAsyncEnumerable<T>
以便在整个系统中使用。 看起来应该有一个辅助方法(例如对于IEnumerable的.ToAsyncEnumerable()
)来帮助解决这个问题,但我找不到任何东西... 我必须实现自己的自定义枚举器吗? (不难,但我不想重复造轮子)
我正在逐步将Ix.NET引入一个旧项目中。 我有许多存储级别的API返回Task<IEnumerable<T>>
,但是我想将它们适应于IAsyncEnumerable<T>
以便在整个系统中使用。 看起来应该有一个辅助方法(例如对于IEnumerable的.ToAsyncEnumerable()
)来帮助解决这个问题,但我找不到任何东西... 我必须实现自己的自定义枚举器吗? (不难,但我不想重复造轮子)
Task<IEnumerable<T>> GetSomeResults<T>()
{
throw new NotImplementedException();
}
async IAsyncEnumerable<T> GetAsyncEnumerable<T>()
{
var results = await GetSomeResults<T>();
foreach(var item in results)
{
yield return item;
}
}
ToAsyncEnumerable()
。 var tasks = new Task[0]; // get your IEnumerable<Task>s
tasks.ToAsyncEnumerable();
AsAsyncEnumerable()
这样的方法。所以这是我最终做的事情,希望能对其他人有所帮助。public static class AsyncEnumerableExtensions {
public struct AsyncEnumerable<T> : IAsyncEnumerable<T> {
private readonly IEnumerable<T> enumerable;
public AsyncEnumerable(IEnumerable<T> enumerable) {
this.enumerable = enumerable;
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()) {
return new AsyncEnumerator<T>(enumerable?.GetEnumerator());
}
}
public struct AsyncEnumerator<T> : IAsyncEnumerator<T> {
private readonly IEnumerator<T> enumerator;
public AsyncEnumerator(IEnumerator<T> enumerator) {
this.enumerator = enumerator;
}
public ValueTask DisposeAsync() {
enumerator?.Dispose();
return default;
}
public ValueTask<bool> MoveNextAsync() {
return new ValueTask<bool>(enumerator == null ? false : enumerator.MoveNext());
}
public T Current => enumerator.Current;
}
public static AsyncEnumerable<T> AsAsyncEnumerable<T>(this IEnumerable<T> that) {
return new AsyncEnumerable<T>(that);
}
public static AsyncEnumerator<T> AsAsyncEnumerator<T>(this IEnumerator<T> that) {
return new AsyncEnumerator<T>(that);
}
}
AsAsyncEnumerable
这样的方法已经存在于dotnetfoundation拥有的System.Linq.Async包中,并且它被命名为ToAsyncEnumerable
。 - Theodor Zouliaspublic static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerable<T> enumerable)
{
using IEnumerator<T> enumerator = enumerable.GetEnumerator();
while (await Task.Run(enumerator.MoveNext).ConfigureAwait(false))
{
yield return enumerator.Current;
}
}
Task<IEnumerable<T>>
是一种异步生成 IEnumerable<T>
的方法。IEnumerable<T>
是同步还是异步生成的,整个列表将被作为HTTP响应发送。IAsyncEnumerable<T>
。IAsyncEnumerable<T>
用于从源异步拉取数据。我没有看到在 WebAPI 上这样做的直接优势。推送到客户端的是 IEnumerable<T>
。也许如果您能展示一些代码... - Paulo MorgadoTask<IEnumerable<T>>
创建一个IAsyncEnumerable<T>
,我只是在寻找最优雅的方法来实现它(而不编写自己的枚举器)。 - Kevin Halversoninterface IDataSource<T> { IAsyncEnumerable<T> GetData(); }
...而我用于获取数据的客户端具有以下签名:class OldDatabaseClient<T> { Task<IEnumerable<T>> GetData() }
最简单(相对高效)的实现接口的方法是什么? - Kevin Halverson
IAsyncEnumerable<T>
而不是IObservable<T>
? - EnigmativityIAsyncEnumerable<T>
以便与 C# 8.0 异步流保持一致(我最终想采用这种方案)。在客户端,我将把由此可枚举对象产生的响应流包装在一个可观察对象中。 - Kevin Halverson