Створіть порожній IAsyncEnumerable


25

У мене є інтерфейс, який написаний так:

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

Я хочу написати порожню реалізацію, яка не повертає жоден елемент, як-от так:

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

Якби це була звичайна БЕЗПЕЧНА Я return Enumerable.Empty<string>();, але я не знайшла жодної AsyncEnumerable.Empty<string>().

Обхідні шляхи

Я знайшов це, що працює, але досить дивно:

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

Будь-яка ідея?

Відповіді:


28

Якщо ви встановите System.Linq.Asyncпакет, ви зможете використовувати його AsyncEnumable.Empty<string>(). Ось повний приклад:

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

Дякуємо за вашу швидку відповідь та пропозицію. Я сподівався, що щось існує в рамках.
куб45

@ cube45: Я, як правило, вважаю System.Linq.Async"практично частиною основи". Там дуже мало , що це тільки в netstandard2.1 , коли мова йде IAsyncEnumerable<T>.
Джон Скіт

@ cube45 Я був би обережним щодо того, щоб не використовувати пакет, є багато кварків з потоками асинхронізації, які ви виявите, коли ви почнете використовувати його більше, якщо ви дійсно не знаєте, що ви робите, я б дійсно опинився на самороді.
Філіп

Дякую за відповіді Я ніколи раніше не використовував IAsyncEnumerable, і я просто експериментував, не роблячи щось "по-справжньому". Ви, мабуть, праві, пакет може бути корисним.
куб45

Виникає проблема, якщо вона використовується з efcore github.com/dotnet/efcore/isissue/18124
Павло Шастов

11

Якщо з будь-якої причини ви не хочете встановлювати пакет, який згадується у відповіді Йона, ви можете створити такий метод 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);
    }
}

Примітка . Відповідь не перешкоджає використанню System.Linq.Asyncпакету. Ця відповідь дає коротку реалізацію AsyncEnumerable.Empty<T>()випадків, які вам потрібні, і ви не можете / не бажаєте використовувати пакет. Ви можете знайти реалізацію, використану в пакеті, тут .


Дякую за вашу відповідь. Дійсно, і це був би варіант. Я думаю, що я вважаю за краще такий спосіб, а не інший пакет. Я відзначу це як прийняте. Нітпік: Ви кажете "метод розширення", хоча це лише статичний метод у статичному класі.
куб45

1
@ cube45: Отже, ви не плануєте використовувати будь-яку функцію LINQ з асинхронними послідовностями? Тому що, як тільки ви захочете зробити все, що зазвичай робите з синхронним LINQ, вам знадобиться System.Linq.Async.
Джон Скіт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.