Criar IAsyncEnumerable vazio


25

Eu tenho uma interface que é escrita assim:

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

Eu quero escrever uma implementação vazia que não retorna nenhum item, assim:

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

Se fosse um IEnumerable simples, eu o faria return Enumerable.Empty<string>();, mas não encontrei nenhum AsyncEnumerable.Empty<string>().

Soluções alternativas

Achei isso que funciona, mas é bastante estranho:

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

Qualquer ideia?

Respostas:


28

Se você instalar o System.Linq.Asyncpacote, poderá usar AsyncEnumable.Empty<string>(). Aqui está um exemplo 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
    }
}

Obrigado pela sua pronta resposta e pela sugestão. Eu esperava que algo existisse na estrutura.
precisa saber é

@ cube45: Eu geralmente consideraria System.Linq.Async"virtualmente parte da estrutura". Há muito pouco que é apenas em netstandard2.1 quando se trata de IAsyncEnumerable<T>.
Jon Skeet

@ cube45 Gostaria de ter cuidado ao não usar o pacote. Existem muitos quarks com fluxos assíncronos que você descobrirá quando começar a usá-lo mais, a menos que saiba realmente o que está fazendo.
Filip Cordas

Obrigado por suas respostas. Eu nunca usei o IAsyncEnumerable antes e estava apenas experimentando, não fazendo algo "de verdade". Você provavelmente está certo, o pacote pode ser útil.
cube45

Existe um problema se ele estiver sendo usado com efcore github.com/dotnet/efcore/issues/18124
Pavel Shastov

11

Se, por algum motivo, você não quiser instalar o pacote mencionado na resposta de Jon, poderá criar o método da AsyncEnumerable.Empty<T>()seguinte maneira:

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: A resposta não desencoraja o uso do System.Linq.Asyncpacote. Esta resposta fornece uma breve implementação dos AsyncEnumerable.Empty<T>()casos que você precisa e não pode / não deseja usar o pacote. Você pode encontrar a implementação usada no pacote aqui .


Obrigado pela sua resposta. De fato, isso seria uma opção também. Eu acho que prefiro dessa maneira do que instalar outro pacote. Vou marcar este como aceito. Nitpick: Você diz "método de extensão" enquanto é apenas um método estático em uma classe estática.
cube45

11
@ cube45: Então você não planeja usar nenhuma funcionalidade LINQ com as sequências assíncronas envolvidas? Como assim que você deseja fazer qualquer coisa que normalmente faria com o LINQ síncrono, precisará do System.Linq.Async.
Jon Skeet
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.