Erstellen Sie eine leere IAsyncEnumerable

25

Ich habe eine Schnittstelle, die so geschrieben ist:

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

Ich möchte eine leere Implementierung schreiben, die kein Element zurückgibt, wie folgt:

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

Wenn es eine einfache IEnumerable wäre return Enumerable.Empty<string>();, würde ich , aber ich habe keine gefunden AsyncEnumerable.Empty<string>().

Problemumgehungen

Ich fand das, was funktioniert, aber ziemlich seltsam ist:

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

Irgendeine Idee?

cube45
quelle

Antworten:

28

Wenn Sie das System.Linq.AsyncPaket installieren , sollten Sie es verwenden können AsyncEnumable.Empty<string>(). Hier ist ein vollständiges Beispiel:

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
quelle
Vielen Dank für Ihre schnelle Antwort und den Vorschlag. Ich hatte gehofft, dass etwas im Rahmen existiert.
cube45
@ cube45: Ich würde allgemein System.Linq.Asyncals "praktisch Teil des Frameworks" betrachten. Es gibt sehr wenig, was nur in netstandard2.1 zu finden ist, wenn es darum geht IAsyncEnumerable<T>.
Jon Skeet
@ cube45 Ich würde vorsichtig sein, wenn ich das Paket nicht benutze. Es gibt viele Quarks mit asynchronen Flows, die Sie entdecken werden, wenn Sie es häufiger verwenden, es sei denn, Sie wissen wirklich, was Sie tun. Ich würde es wirklich auf dem Nugget tun.
Filip Cordas
Danke für deine Antworten. Ich habe IAsyncEnumerable noch nie zuvor verwendet, und ich habe nur experimentiert und nichts "wirklich" getan. Sie haben wahrscheinlich Recht, das Paket könnte nützlich sein.
cube45
Es gibt ein Problem, wenn es mit efcore github.com/dotnet/efcore/issues/18124
Pavel Shastov
11

Wenn Sie das in Jons Antwort erwähnte Paket aus irgendeinem Grund nicht installieren möchten, können Sie die folgende Methode erstellen AsyncEnumerable.Empty<T>():

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

Hinweis: Die Antwort entmutigt Sie nicht, das System.Linq.AsyncPaket zu verwenden. Diese Antwort enthält eine kurze Implementierung AsyncEnumerable.Empty<T>()für Fälle, in denen Sie sie benötigen und das Paket nicht verwenden können / möchten. Die im Paket verwendete Implementierung finden Sie hier .

Reza Aghaei
quelle
Danke für deine Antwort. In der Tat wäre das auch eine Option. Ich denke, dass ich diesen Weg vorziehen würde, anstatt ein anderes Paket zu installieren. Ich werde diesen als akzeptiert markieren. Nitpick: Sie sagen "Erweiterungsmethode", während es sich nur um eine statische Methode in einer statischen Klasse handelt.
cube45
1
@ cube45: Planen Sie also nicht, eine LINQ-Funktionalität mit den beteiligten asynchronen Sequenzen zu verwenden? Denn sobald Sie etwas tun möchten, was Sie normalerweise mit synchronem LINQ tun würden, benötigen Sie System.Linq.Async.
Jon Skeet