Crear IAsyncEnumerable vacío


25

Tengo una interfaz que se escribe así:

public interface IItemRetriever
{
    public IAsyncEnumerable<string> GetItemsAsync();
}

Quiero escribir una implementación vacía que no devuelva ningún elemento, así:

public class EmptyItemRetriever : IItemRetriever
{
    public IAsyncEnumerable<string> GetItemsAsync()
    {
       // What do I put here if nothing is to be done?
    }
}

Si fuera un IEnumerable simple, lo haría return Enumerable.Empty<string>();, pero no encontré ninguno AsyncEnumerable.Empty<string>().

Soluciones alternativas

Encontré esto que funciona pero es bastante extraño:

public async IAsyncEnumerable<string> GetItemsAsync()
{
    await Task.CompletedTask;
    yield break;
}

¿Alguna idea?

Respuestas:


28

Si instala el System.Linq.Asyncpaquete, debería poder usarlo AsyncEnumable.Empty<string>(). Aquí hay un ejemplo completo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        IAsyncEnumerable<string> empty = AsyncEnumerable.Empty<string>();
        var count = await empty.CountAsync();
        Console.WriteLine(count); // Prints 0
    }
}

Gracias por su pronta respuesta y la sugerencia. Esperaba que algo existiera en el marco.
— cubo45

@ cube45: generalmente lo consideraría System.Linq.Asynccomo "prácticamente parte del marco". Hay muy poco lo que es justo en netstandard2.1 cuando se trata de IAsyncEnumerable<T>.
— Jon Skeet

@ cube45 Tendría cuidado de no usar el paquete, hay muchos quarks con flujos asíncronos que descubrirá cuando comience a usarlo más, a menos que realmente sepa lo que está haciendo, realmente lo haría en la pepita.
— Filip Cordas

Gracias por tus respuestas. Nunca usé IAsyncEnumerable antes, y solo estaba experimentando, no haciendo algo "de verdad". Probablemente tengas razón, el paquete puede ser útil.
— cube45

Hay un problema si se utiliza con efcore github.com/dotnet/efcore/issues/18124
— Pavel Shastov

11

Si por alguna razón no desea instalar el paquete que se menciona en la respuesta de Jon, puede crear el método de AsyncEnumerable.Empty<T>()esta manera:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public static class AsyncEnumerable
{
    public static IAsyncEnumerator<T> Empty<T>() => EmptyAsyncEnumerator<T>.Instance;

    class EmptyAsyncEnumerator<T> : IAsyncEnumerator<T>
    {
        public static readonly EmptyAsyncEnumerator<T> Instance = 
            new EmptyAsyncEnumerator<T>();
        public T Current => default!;
        public ValueTask DisposeAsync() => default;
        public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(false);
    }
}

Nota: La respuesta no desalienta el uso del System.Linq.Asyncpaquete. Esta respuesta proporciona una breve implementación de los AsyncEnumerable.Empty<T>()casos en los que lo necesita y no puede / no quiere usar el paquete. Puede encontrar la implementación utilizada en el paquete aquí .


Gracias por tu respuesta. De hecho, esa también sería una opción. Creo que preferiría eso en lugar de instalar otro paquete. Marcaré este como aceptado. Nitpick: Dices "método de extensión" mientras que es solo un método estático en una clase estática.
— cube45

1
@ cube45: Entonces, ¿no planea usar ninguna funcionalidad LINQ con las secuencias asincrónicas involucradas? Porque tan pronto como desee hacer algo que normalmente haría con LINQ síncrono, necesitará System.Linq.Async.
— Jon Skeet
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.