Скажем, у меня есть последовательность целых чисел, которые я получаю асинхронно.
async Task<int> GetI(int i){
return await Task.Delay(1000).ContinueWith(x => i);
}
Я хочу создать генератор над этой последовательностью, если бы последовательность была синхронной, я бы сделал:
IEnumerable<int> Method()
{
for (var i = 0; i < 100; i++)
{
yield return GetI(i); // won't work, since getI returns a task
}
}
Итак, я решил, что аналогия делает генератор асинхронным и уступает ему:
async Task<IEnumerable<int>> Method()
{
for (var i = 0; i < 100; i++)
{
yield return await Task.Delay(1000).ContinueWith(x => i);
}
}
Это не сработает, так как метод с yield
должен возвращать IEnumerable
что-то, альтернатива, которая имеет больше смысла IEnumerable<Task<int>>
, но не будет компилироваться, поскольку методы async
должны возвращать Task
или void.
Теперь я понимаю, что могу просто удалить ожидание и вернуть IEnumerable<Task<int>>
, но это не поможет мне, так как итерация будет продолжать запрашивать данные, прежде чем какая-либо из них будет готова, поэтому она не решит мою проблему.
- Есть ли способ хорошо смешивать перечисления и задачи с приятным сахаром, который дает мне язык с ожиданием и выходом?
- Есть ли способ хорошо его использовать?
(Из поиска в Интернете я подозреваю, что ответ на первый вопрос ложный, а второй - наблюдатель/наблюдаемый, но я не нашел никакой канонической ссылки, и мне интересен лучший способ реализовать этот шаблон в С#)