Créer un IAsyncEnumerable vide

25

J'ai une interface qui est écrite comme ceci:

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

Je veux écrire une implémentation vide qui ne renvoie aucun élément, comme ceci:

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

Si c'était un simple IEnumerable, je le ferais return Enumerable.Empty<string>();, mais je n'en ai pas trouvé AsyncEnumerable.Empty<string>().

Solutions de contournement

J'ai trouvé cela qui fonctionne mais qui est assez bizarre:

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

Une idée?

cube45
la source

Réponses:

28

Si vous installez le System.Linq.Asyncpackage, vous devriez pouvoir l'utiliser AsyncEnumable.Empty<string>(). Voici un exemple complet:

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
    }
}
Jon Skeet
la source
Merci pour votre réponse rapide et votre suggestion. J'espérais que quelque chose existe dans le cadre.
cube45
@ cube45: Je considérerais généralement System.Linq.Asynccomme "faisant pratiquement partie du cadre". Il y a très peu de choses qui sont juste dans netstandard2.1 en ce qui concerne IAsyncEnumerable<T>.
Jon Skeet
@ cube45 Je ferais attention à ne pas utiliser le paquet, il y a beaucoup de quarks avec des flux asynchrones que vous découvrirez lorsque vous commencerez à l'utiliser davantage à moins que vous ne sachiez vraiment ce que vous faites, je le ferais vraiment sur le nugget.
Filip Cordas
Merci pour vos réponses. Je n'ai jamais utilisé IAsyncEnumerable auparavant, et je faisais juste des expériences, je ne faisais pas quelque chose "pour de vrai". Vous avez probablement raison, le package peut être utile.
cube45
Il y a un problème s'il est utilisé avec efcore github.com/dotnet/efcore/issues/18124
Pavel Shastov
11

Si pour une raison quelconque vous ne souhaitez pas installer le package mentionné dans la réponse de Jon, vous pouvez créer la méthode AsyncEnumerable.Empty<T>()comme ceci:

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);
    }
}

Remarque: La réponse ne décourage pas l'utilisation du System.Linq.Asyncpackage. Cette réponse fournit une brève implémentation de AsyncEnumerable.Empty<T>()pour les cas où vous en avez besoin et que vous ne pouvez / ne voulez pas utiliser le package. Vous pouvez trouver l'implémentation utilisée dans le package ici .

Reza Aghaei
la source
Merci pour votre réponse. En effet, ce serait également une option. Je pense que je préférerais cette façon plutôt que d'installer un autre paquet. Je marquerai celui-ci comme accepté. Nitpick: Vous dites «méthode d'extension» alors que ce n'est qu'une méthode statique dans une classe statique.
cube45
1
@ cube45: Ne prévoyez-vous donc pas d'utiliser une fonctionnalité LINQ avec les séquences asynchrones impliquées? Parce que dès que vous voulez faire tout ce que vous feriez normalement avec LINQ synchrone, vous aurez besoin de System.Linq.Async.
Jon Skeet