Ответ 1
Вы можете это решить, рассматривая типы в игре. Например, MapToLocalObject
- если рассматривать как асинхронную функцию - отображает от R
до L
. Но если вы рассматриваете его как синхронную функцию, он отображает от R
до Task<L>
.
Task
- это "будущее", поэтому Task<L>
можно рассматривать как тип, который в какой-то момент в будущем будет создавать L
.
Таким образом, вы можете легко преобразовать из последовательности R
в последовательность Task<L>
:
IEnumerable<Task<L>> mappingTasks = remoteItems.Select(remoteItem => MapToLocalObject(remoteItem));
Обратите внимание, что между этим и вашим исходным кодом существует важная смысловая разница. Ваш исходный код ожидает отображения каждого объекта перед тем, как перейти к следующему объекту; этот код будет запускать все сопоставления одновременно.
Ваш результат - последовательность задач - последовательность будущих L
результатов. Для работы с последовательностями задач существует несколько общих операций. Task.WhenAll
и Task.WhenAny
являются встроенными операциями для наиболее распространенных требований. Если вы хотите дождаться завершения всех сопоставлений, вы можете сделать следующее:
L[] mappedItems = await Task.WhenAll(mappingTasks);
Если вы предпочитаете обрабатывать каждый элемент по мере его завершения, вы можете использовать OrderByCompletion
из мою библиотеку AsyncEx:
Task<L>[] orderedMappingTasks = mappingTasks.OrderByCompletion();
foreach (var task in orderedMappingTasks)
{
var mappedItem = await task;
...
}