suppose i have a code already working that goes like this
....
....
foreach(object item in enumerator.GetItems(arg1, arg2....)
{
}
....
....
where getItems
is a method of an abstract class (abstractEnumerator
), and getItems
returns an IEnumerable<object>
.
The problem arises because now i would like to use the Any() LINQ extension before the foreach to check if the enumerable is empty, and i want to be sure that it wont change at all the 'state' of the IEnumerable when it reaches the foreach, in order to make sure that the code behaves exactly as before.
However, the tricky part, is i do not have access to the implementations of abstractEnumerator, and therefore, i do not have access to the underlying implementation of the IEnumerable interface.
For all i know the Reset method of the interface could be returning null without doing anything. Imagine that the implementations of the abstractEnumerator are created by third party developers from another company, so i do not have access to their code.
My question is if i can be sure that the state will remain the same, when adding the Any() before the for each, regardless of the underlying implementation.
According to microsoft reference on Any:
' The enumeration of source is stopped as soon as the result can be determined. '
In this case, that i want to stop on the first element (basically what i want to ask is whether the IEnumerable is empty or not), does this means that the enumeration stops before processing the first element (i.e. the state is the same as if Any() wasnt called, regardless of the implementation), or it stops after processing the first element?
Often enumerables themselves are effectively stateless - the state comes in the enumerator which is returned by GetEnumerator()
. However, if you want to avoid calling GetEnumerator()
twice (which could easily give different results each time, of course), the simplest thing is just to remember whether or not you saw any elements:
bool any = false;
foreach (var element in GetItems(...))
{
any = true;
}
if (any)
{
// whatever
}
That won't help if you want to take an action before the first iteration, of course. If you want to do that, you could use the iterator yourself:
using (var iterator = GetItems(...).GetEnumerator())
{
if (iterator.MoveNext())
{
// Take your "pre-iteration" action
}
do
{
var item = iterator.Current;
// Use the item
} while (iterator.MoveNext());
}
See more on this question at Stackoverflow