IAsyncCursor 如何用于 mongodb c# 驱动程序的迭代?
How is an IAsyncCursor used for iteration with the mongodb c# driver?
我正在尝试获取服务器中所有数据库的列表并最终将它们打印出来(即使用它们的名称作为 string
s)。使用以前版本的 c# 驱动程序,我可以调用 Server.GetDatabases()
,但已替换为 ListDatabasesAsync()
。
return 值是一个 IAsyncCursor<>
,我不确定如何处理它。如何使用这样的游标遍历数据库(或任何东西)列表?
您有 3 个选项:
- 使用内置驱动方法(例如
ForEachAsync
、ToListAsync
)。
- 在 C# 8.0 及更高版本上,您可以将
IAsyncCursor
转换为 IAsyncEnumerable
并使用 await foreach
或任何异步 LINQ 运算符。
- 遍历
IAsyncCursor
。
内置驱动方法
驱动程序有一些类似 LINQ 的扩展方法 IAsyncCursor
,如 AnyAsync
、ToListAsync
等。对于迭代,它有 ForEachAsync
:
var cursor = await client.ListDatabasesAsync();
await cursor.ForEachAsync(db => Console.WriteLine(db["name"]));
正在转换为 IAsyncEnumerable
在 C# 8.0 及更高版本上,使用 await foreach
进行迭代(并使用异步 LINQ)要好得多。这需要将 IAsyncCursor
包装在 IAsyncEnumerable
中。
你可以自己做,但由于正确处理一些关键的事情(比如取消和处置)很重要,我发布了一个 nuget 包:MongoAsyncEnumerableAdapter
var cursor = await client.ListDatabasesAsync();
await foreach (var db in cursor.ToAsyncEnumerable())
{
Console.WriteLine(db["name"]);
}
自定义迭代
C# 中的传统迭代是使用 IEnumerable
和 foreach
完成的。 foreach
是编译器的语法糖。它实际上是对 GetEnumerator
、using
作用域和 while
循环的调用:
using (var enumerator = enumerable.GetEnumerator())
{
while (enumerator.MoveNext())
{
var current = enumerator.Current;
// use current.
}
}
IAsyncCursor
等价于 IEnumerator
(IEnumerable.GetEnumerator
的结果),而 IAsyncCursorSource
等价于 IEnumerable
。不同之处在于这些支持 async
(并且每次迭代都获得一批,而不仅仅是单个项目)。所以你可以自己实现整个 using
, while
循环:
IAsyncCursorSource<int> cursorSource = null;
using (var asyncCursor = await cursorSource.ToCursorAsync())
{
while (await asyncCursor.MoveNextAsync())
{
foreach (var current in asyncCursor.Current)
{
// use current
}
}
}
我个人喜欢将游标转换为 C# 8 IAsyncEnumerable
,这样您就可以获得使用枚举的所有好处(LINQ
主要)。
使用@i3arnon 的“长答案”我创建了这个扩展方法:
public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IAsyncCursor<T> asyncCursor)
{
while (await asyncCursor.MoveNextAsync())
{
foreach (var current in asyncCursor.Current)
{
yield return current;
}
}
}
由于 C# 9 中 GetAsyncEnumerator
扩展方法的支持和 foreach
的鸭子类型实现,现在可以使用以下扩展方法直接迭代游标:
public static class MongoDbCursorExtensions
{
public static IAsyncCursor<T> GetAsyncEnumerator<T>(this IAsyncCursor<T> cursor) => cursor;
}
用法:
var cursor = await collection.Find(filter).ToCursorAsync();
await foreach (var batch in cursor) // extension method implicitly called here
{
foreach (var item in batch)
{
// ...
}
}
我正在尝试获取服务器中所有数据库的列表并最终将它们打印出来(即使用它们的名称作为 string
s)。使用以前版本的 c# 驱动程序,我可以调用 Server.GetDatabases()
,但已替换为 ListDatabasesAsync()
。
return 值是一个 IAsyncCursor<>
,我不确定如何处理它。如何使用这样的游标遍历数据库(或任何东西)列表?
您有 3 个选项:
- 使用内置驱动方法(例如
ForEachAsync
、ToListAsync
)。 - 在 C# 8.0 及更高版本上,您可以将
IAsyncCursor
转换为IAsyncEnumerable
并使用await foreach
或任何异步 LINQ 运算符。 - 遍历
IAsyncCursor
。
内置驱动方法
驱动程序有一些类似 LINQ 的扩展方法 IAsyncCursor
,如 AnyAsync
、ToListAsync
等。对于迭代,它有 ForEachAsync
:
var cursor = await client.ListDatabasesAsync();
await cursor.ForEachAsync(db => Console.WriteLine(db["name"]));
正在转换为 IAsyncEnumerable
在 C# 8.0 及更高版本上,使用 await foreach
进行迭代(并使用异步 LINQ)要好得多。这需要将 IAsyncCursor
包装在 IAsyncEnumerable
中。
你可以自己做,但由于正确处理一些关键的事情(比如取消和处置)很重要,我发布了一个 nuget 包:MongoAsyncEnumerableAdapter
var cursor = await client.ListDatabasesAsync();
await foreach (var db in cursor.ToAsyncEnumerable())
{
Console.WriteLine(db["name"]);
}
自定义迭代
C# 中的传统迭代是使用 IEnumerable
和 foreach
完成的。 foreach
是编译器的语法糖。它实际上是对 GetEnumerator
、using
作用域和 while
循环的调用:
using (var enumerator = enumerable.GetEnumerator())
{
while (enumerator.MoveNext())
{
var current = enumerator.Current;
// use current.
}
}
IAsyncCursor
等价于 IEnumerator
(IEnumerable.GetEnumerator
的结果),而 IAsyncCursorSource
等价于 IEnumerable
。不同之处在于这些支持 async
(并且每次迭代都获得一批,而不仅仅是单个项目)。所以你可以自己实现整个 using
, while
循环:
IAsyncCursorSource<int> cursorSource = null;
using (var asyncCursor = await cursorSource.ToCursorAsync())
{
while (await asyncCursor.MoveNextAsync())
{
foreach (var current in asyncCursor.Current)
{
// use current
}
}
}
我个人喜欢将游标转换为 C# 8 IAsyncEnumerable
,这样您就可以获得使用枚举的所有好处(LINQ
主要)。
使用@i3arnon 的“长答案”我创建了这个扩展方法:
public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IAsyncCursor<T> asyncCursor)
{
while (await asyncCursor.MoveNextAsync())
{
foreach (var current in asyncCursor.Current)
{
yield return current;
}
}
}
由于 C# 9 中 GetAsyncEnumerator
扩展方法的支持和 foreach
的鸭子类型实现,现在可以使用以下扩展方法直接迭代游标:
public static class MongoDbCursorExtensions
{
public static IAsyncCursor<T> GetAsyncEnumerator<T>(this IAsyncCursor<T> cursor) => cursor;
}
用法:
var cursor = await collection.Find(filter).ToCursorAsync();
await foreach (var batch in cursor) // extension method implicitly called here
{
foreach (var item in batch)
{
// ...
}
}