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.