Tengo un método asíncrono que devuelve un IAsyncEnumerable usando yield. En algunos casos, puede ser necesario obtener los elementos de forma sincrónica, por lo que quiero crear otro método para esto que devuelva IEnumerable ejecutando el método existente de forma sincrónica para evitar el código duplicado.
async IAsyncEnumerable<Foo> GetItemsAsync() { yield return ... } IEnumerable<Foo> GetItems() => GetItemsAsync() // Run shyncronouslyLeí muchas soluciones sobre la ejecución de métodos asincrónicos sincrónicamente usando técnicas como Task.RunSynchronously o simplemente llamándolo en un contexto de sincronización e ignorando la advertencia. Sin embargo, parece que ninguno de estos es posible en el caso de enumerables asíncronos. La interfaz no presenta ningún método RunSynchronously y tratar de enumerar mediante un foreach que no se espera provoca un error de compilación. Obtener el enumerador y ejecutar MoveNext sincrónicamente tampoco parece ser una opción, ya que ese método devuelve ValueTask, que no presenta métodos de espera y necesito capturar el resultado de la tarea para saber cuándo dejar de iterar.
Entonces, ¿es posible forzar mi método enumerador asíncrono sincrónicamente y obtener el resultado como IEnumerable y, de ser así, cómo?
Puede usar el método de extensión ToEnumerable del paquete System.Linq.Async . La firma de este método es:
public static IEnumerable<TSource> ToEnumerable<TSource>( this IAsyncEnumerable<TSource> source)... y podrías usarlo así:
IEnumerable<Foo> GetItems() => GetItemsAsync().ToEnumerable(); Actualización: es posible que se incluya un método de extensión ToBlockingEnumerable con una funcionalidad idéntica en la próxima versión de la plataforma .NET (.NET 7). Problema de GitHub relacionado: Agregue un método de extensión IAsyncEnumerable.ToEnumerable .