Как использовать async перечисления?

У меня есть метод с этим возвращаемым типом:

public async Task<IEnumerable<T>> GetAll()

Он делает некоторые дальнейшие асинхронные вызовы (неизвестный номер), каждый из которых возвращает задачу перечислимого T, а затем хочет согласовать результаты для возврата.

var data1 = src1.GetAll();
var data2 = src2.GetAll();
var data3 = src3.GetAll(); //and so on

Теперь достаточно легко подождать всех и конкатрировать результаты, чтобы произвести единый перечислимый, но я хотел бы, чтобы перечисляемый был доступен, как только первый вызов вернется, с потенциальным ожиданием для вызывающего/перечислителя, если какие-либо вызовы все еще ожидается, когда закончится доступный результат.

Нужно ли мне руковать concat для этого, работая над отсутствием поддержки перечислителя, когда он завершает задачу < > ? Или там уже есть вызов библиотеки в TPL или в другом месте, что могло бы мне помочь. Я смотрел на IX, но он все еще находится на экспериментальном выпуске и не хочу его сбрасывать.

На стороне примечания, это то, что я пытаюсь использовать анти-шаблон? Я могу придумать одно осложнение, обработку исключений - со стороны вызывающего абонента, вызов может завершиться успешно, и он начнет использовать перечислимый, но он может взорваться на полпути через это...

Ответ 1

Существует существующий проект под названием Async Enumerable, который точно отвечает на эту проблему.

Вы можете использовать его довольно легко.

Например:

IAsyncEnumerable<string> GetAsyncAnswers()
{
    return AsyncEnum.Enumerate<string>(async consumer =>
    {
        foreach (var question in GetQuestions())
        {
            string theAnswer = await answeringService.GetAnswer(question);
            await consumer.YieldAsync(theAnswer);
        }
    });
}

Это предоставляет IAsyncEnumerable<string>, который возвращает один раз GetAnswer. Вы можете внутренне выставить IAsyncEnumerable<T> в своем случае и внутренне совершать вызовы внутри GetAll.

что я пытаюсь создать анти-шаблон? Я могу придумать одно осложнение, обработка исключений - со стороны вызывающего абонента вызов может завершаться успешно, и он начинает использовать перечислимое, но может взорваться в середине этого...

Я бы так не сказал. У этого есть потенциально проблемы, такие как исключение, происходящее внутри во время одного из ожиданий, но это также может произойти внутри любого IEnumerable<T>. Асинхронные последовательности - это то, что необходимо в сегодняшней реальности новых асинхронных API.