I'm trying to optimize a routine that looks sort of like this (simplified):
public async Task<IEnumerable<Bar>> GetBars(ObjectId id){
var output = new Collection<Bar>();
var page = 1;
var hasMore = true;
while(hasMore) {
var foos = await client.GetFoos(id, page);
foreach(var foo : foos) {
if(!Proceed(foo)) {
hasMore = false;
break;
}
output.Add(new Bar().Map(foo)
}
page++;
return output;
}
The method that calls GetBars()
looks something like this
public async Task<Baz> GetBaz(ObjectId id){
var bars = await qux.GetBars();
if(bars.Any() {
var bazBaseData = qux.GetBazBaseData(id);
var bazAdditionalData = qux.GetBazAdditionalData(id);
return new Baz().Map(await bazBaseData, await bazAdditionalData, bars);
}
}
GetBaz()
returns between 0 and a lot of items. Since we run through a few million id's we initially added the if(bars.Any())
statement as an initial attempt of speeding up the application.
Since the GetBars()
is awaited it blocks the thread until it has collected all its data (which can take some time). My idea was to use yield return and then replace the if(bars.Any())
with a check that tests if we get at least one element, so we can fire off the two other async methods in the meantime (which also takes some time to execute).
My question is then how to do this. I know System.Linq.Count()
and System.Linq.Any()
defeats the whole idea of yield return and if I check the first item in the enumerable it is removed from the enumerable.
Is there another/better option besides adding for instance an out parameter to GetBars()
?
TL;DR: How do I check whether an enumerable from a yield return contains any objects without starting to iterate it?