Запустить перечисление IAsyncEnumerable дважды невозможно? - PullRequest
4 голосов
/ 17 марта 2020

Выполнить перечисление IAsyncEnumerable дважды невозможно?

После запуска CountAsync await foreach не будет перечислять ни один элемент. Почему? Похоже, что для метода AsyncEnumerator.

var count = await itemsToImport.CountAsync();

await foreach (var importEntity in itemsToImport)
{
    // won't run
}

нет источника сброса

private IAsyncEnumerable<TEntity> InternalImportFromStream(TextReader reader)
{
    var csvReader = new CsvReader(reader, Config);

    return csvReader.GetRecordsAsync<TEntity>();
}

Ответы [ 2 ]

5 голосов
/ 17 марта 2020

Это не имеет никакого отношения к сбросу IAsyncEnumerator. Этот код пытается сгенерировать второй IAsyncEnumerator, который, как и в IEnumerable.GetEnumerator (), возможен только в некоторых видах коллекций. Если Enumerable (asyn c или нет) является абстракцией над некоторой структурой данных, предназначенной только для пересылки, то GetEnumerator / GetAsyncEnumerator завершится ошибкой.

И даже когда это не выходит из строя, иногда это дорого. Например, он может выполнять запрос к базе данных или обращаться к удаленному API каждый раз, когда перечисляется. Вот почему IEnumerable / IAsyncEnumerable заставляет плохие publi c возвращать типы из функций, так как они не описывают возможности возвращаемой коллекции, и почти единственное, что вы можете сделать со значением, это материализовать его с помощью .ToList / ToListAsyn c.

Например, это прекрасно работает:

static async IAsyncEnumerable<int> Col()
{
    for (int i = 1; i <= 10; i++)
    {
        yield return i;
    }
}
static void Main(string[] args)
{
    Run().Wait();
}
static async Task Run()
{

    var col = Col();

    var count = await col.CountAsync();
    await foreach (var dataPoint in col)
    {
        Console.WriteLine(dataPoint);
    }
}
0 голосов
/ 17 марта 2020

Кажется невозможным сбросить IAsyncEnumerable самим интерфейсом из-за того, что в интерфейсе IAsyncEnumerator отсутствует метод Reset.

В этом конкретном примере c второе перечисление не будет работать, поскольку объект IAsyncEnumerable предназначен для потока. Как только поток прочитан, позиционный курсор нацелен на конец потока. если у вас есть контроль над потоком или ссылка на него (что я не имею), вы можете снова установить позицию в 0 и перечислить ее снова.

Я склонен использовать ToListAsyn c, а затем получить считать из его свойства Count и выполнять итерации элементов синхронно, потому что они уже загружены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...