I have a function that accepts an Enumerable. I need to ensure that the enumerator is evaluated, but I'd rather not create a copy of it (e.g. via ToList() or ToArray()) if it is all ready in a List or some other "frozen" collection. By Frozen I mean collections where the set of items is already established e.g. List, Array, FsharpSet, Collection etc, as opposed to linq stuff like Select() and where().
Is it possible to create a function "ForceEvaluation" that can determine if the enumerable has deffered execution pending, and then evaluate the enumerable?
public void Process(IEnumerable<Foo> foos)
{
IEnumerable<Foo> evalutedFoos = ForceEvaluation(foos)
EnterLockedMode(); // all the deferred processing needs to have been done before this line.
foreach (Foo foo in foos)
{
Bar(foo);
}
}
public IEnumerable ForceEvaluation(IEnumerable<Foo> foos)
{
if(??????)
{ return foos}
else
{return foos.ToList()}
}
}
After some more research I've realized that this is pretty much impossible in any practical sense, and would require complex code inspection of each iterator.
So I'm going to go with a variant of Mark's answer and create a white-list of known safe types and just call ToList() anything not on that is not on the white-list.
Thank you all for your help.
Edit* After even more reflection, I've realized that this is equivalent to the halting problem. So very impossible.
if (foos is IList<Foo>)
, although this is probably a hack. This works even whenfoos
is an array. – Carderwhile(true) { yield return 1; }
? I suspect you're probably doing something wrong. Also, those that are suggestingif(foos is
IList<Foo>)
aren't realizing thatIList<Foo>
can be lazily implemented too. – ReligioseIQueryable
). If so, then check for theIQueryable
type and runToList()
against that). – Backhandfor(int i = 0; i < 42; i++) yield return Randon.Next();
where every execution produces a completely different sequence? – Religiose