I have a following code in my graph library:
while(true) {
using (var i = ancestry.GetAdjacent(current).GetEnumerator())
{
if (!i.MoveNext())
yield break;
if (i.MoveNext())
throw new InvalidOperationException("ancestry graph can only have one adjacent vertex for any given vertex");
// it's a bug, as some enumerators could return null after failed MoveNext().
current = i.Current;
if (isSentinel(current))
yield break;
}
}
This code works for some instances of IEnumerator, and fails for others (all standard implementations from .NET, plus iterator methods with yield return.
Is that behaviour unspecified?
If not, what is the correct notation? Leave Current at previous, or set to default(T)?
UPDATE:
I have explored some of the implementations of IEnumerator for collections, Linq extensions as well as typed array: fiddle.
In my understanding, Linq violates the contract of IEnumerable, as it does not throw on Current beyond the end of enumeration, and typed array violates the contract of IEnumerable, as it throws on IEnumerable<T>.Current
, and there are no exception types specified for IEnumerable.Current.
Can someone clarify, what does it mean 'undefined' when it's stated in documentation? Does it include throwing unspecified exceptions:
From IEnumerator.Current Property documentation:
Current is undefined under any of the following conditions: The enumerator is positioned before the first element in the collection, immediately after the enumerator is created. MoveNext must be called to advance the enumerator to the first element of the collection before reading the value of Current. The last call to MoveNext returned false, which indicates the end of the collection. The enumerator is invalidated due to changes made in the collection, such as adding, modifying, or deleting elements. Current returns the same object until MoveNext is called. MoveNext sets Current to the next element.