11

У меня есть метод с этим возвращаемым типом:Как включить async перечисления?

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

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

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

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

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

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

+0

(Как примечание) Ваш шаблон кажется асимметричным: код _ ожидает, что первая последовательность будет готова, но не ждет остальное. – Vlad

+5

Возможно, вам действительно нужно 'IObservable '? В этом случае вы можете просто использовать [Observable.Concat'] (https://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.concat%28v=vs.103%29.aspx). – Vlad

+0

@ Vlad: Хорошая точка. Я думал об этом, когда смотрел в Ix/Rx, и я согласен, реактивный, как правило, лучше подходит для этого типа прецедентов. Но общий сценарий и приложение являются основанными на тяге, и я не хочу бросать в Rx-молот, чтобы вернуться к перечисляемым из наблюдаемого результата. – Vivek

ответ

6

Существует существующий проект под названием 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.

+1

Спасибо. Отмечено как ответ. Я не импортировал библиотеку, но закончил, качаясь в любом случае в одной строке с вашим образцом, с помощью конкатенатора, использующего func для получения следующего перечисления. Возможно, я еще раз взгляну на библиотеку, если я получу более широкий вариант использования. – Vivek

Смежные вопросы