tl; dr Итераторы, реализованные с yield, являются блокирующей конструкцией, поэтому на данный момент await и yield несовместимы.
Long Поскольку итерация поIEnumerable
является блокирующей операцией, вызов метода, отмеченного как async
, все равно будет выполнять его блокирующим образом, поскольку он должен ждать завершения этой операции.
async Task<IEnumerable<Foo>> Method(String [] Strs)
{
foreach(var str in strs)
{
yield return await DoSomethingAsync( str)
}
}
Ожидание Method
смешивает значения.Вы хотите подождать, пока Task
не получит IEnumerable
, а затем заблокировать итерацию по нему?Или вы пытаетесь дождаться каждого значения IEnumerable
?
Я предполагаю, что второе - это желаемое поведение, и в этом случае существующая семантика итератора не будет работать.Интерфейс IEnumerator<T>
в основном
public interface IEnumerator<T>
T Current;
bool MoveNext();
}
Я игнорирую Reset()
, поскольку он не имеет смысла для последовательности асинхронных результатов.Но то, что вам нужно, это что-то вроде этого:
public interface IAsyncEnumerator<T>
T Current;
Task<bool> MoveNext();
}
Конечно, foreach
также не будет работать с этим, и вам придется выполнять итерации вручную, как это:
var moveNext = await asyncEnumerator.MoveNext();
while(moveNext) {
// get the value that was fetche asynchronously
var v = asyncEnumerator.Current;
// do something with that value
// suspend current execution context until next value arrives or we are done
moveNext = await asyncEnumerator.MoveNext();
}