I have a function that gets a sequence of items:
List<MyType> GetPage(int pageNr) {...} To get all available items you could do something like:
IEnumerable<MyType> FetchMyItems() { int pageNr = 0; var fetchedItems = GetPage(pageNr); while (fetchedItems.Any() { // there are items to return // yield return the fetched items: foreach (var fetchedItem in fetchedItems) yield return fetchedItems; // get the next page ++pageNr; fetchedItems = GetPage(pageNr) } } Using this method, my users won't have to fetch the items per page anymore, if they need only a few items only the first page will be fetched. More pages will be fetched automatically when they need more items. The disadvantage is of course that I sometimes fetch a few more items that won't be used.
I want an async version for this
So I have the following GetPage:
async Task<List<MyType>> GetPageAsync(int pageNr) {...} From what I understand from IEnumerable, is that it doesn't create the resulting sequence, it only creates the possibility to enumerate this sequence.
This enumerating is done explicitly using 'foreach', or implicitly using LINQ functions like 'ToList', 'ToArray', but also functions like 'FirstOrDefault', 'Any', Sum.
var fetchItemTasks = FetchMyItemsAsync(); foreach (var fetchItemTask in fetchedItemTasks) { MyType fetchedItem = await fetchItemTask; Process(fetchedItem); } Or if you do this low level:
var myitemsEnumerable = fetchMyItemsAsync(); // don't await yet, only create the possibility to enumerate var enumerator = myItemsEnumerable.GetEnumerator(); while (enumerator.MoveNext()) { // there is an item available in current: Task<MyType> task = enumerator.Current; return task; } Looking at this, It seems that the function should not return Task<IEnumerable<MyType>> but IEnumerable<Task<MyType>>, if you want to access an element you'll have to await for this.
Therefore, the function that returns the possibility to enumerate over awaitable items is not async for itself. You don't await for the enumerable, this enumerable can be created without accessing slow providers like a database. The items in the enumerable sequence are awaitable:
IEnumerable<Task<MyType>> FetchMyItems() { int pageNr = 0; Task<List<MyType>> fetchItemTask = GetPageAsync(pageNr); And now? If I await fetchItemTask, the items are already local nothing to await for anymore. If I fetchItemTask.Wait(), the function blocks.
ToListAsync,ToArrayAsync,CountAsync,AnyAsyncetc. But for them I need a basic IEnumerable. I'll read your proposal and check if creating my ownEnumeratorAsync<TSource>would be the way to go