using System; using System.Collections; using System.Collections.Generic; namespace Chernobyl.Collections.Generic.Hierarchy { /// /// A helper class for implementing s that /// iterate over trees. /// /// The type that contains a list of instances of it's /// own type (a class that acts as a node in a tree). public abstract class TreeEnumerator : IEnumerator { /// /// Initializes a new instance of the /// class. /// /// The inclusive node to start from (it will /// become the first value of . /// The method that retrieves the /// from an instance of type /// . Typically, it will look something like /// this (using a lambda expression): /// /// foobar => foobar.Children.GetEnumerator(); /// /// protected TreeEnumerator(T startingNode, Func> getChildEnumerator) { EnumeratorLevels = new LinkedList>(); Start = startingNode; GetChildEnumerator = getChildEnumerator; ResetInternal(); } /// /// Gets the element in the collection at the current position of the /// enumerator. /// /// The element in the collection at the current position of /// the enumerator. /// The enumerator is /// positioned before the first element of the collection or after the /// last element or the collection was modified after the enumerator /// was created. public virtual T Current { get { if (Started == false) throw new InvalidOperationException("The enumerator is positioned " + "before the first element of the collection or after the last. Please " + "call the MoveNext() method on the enumerator before calling the Current property."); return _current; } set { _current = value; } } /// /// Performs application-defined tasks associated with freeing, /// releasing, or resetting unmanaged resources. /// public virtual void Dispose() { } /// /// Gets the element in the collection at the current position of the /// enumerator. /// /// The element in the collection at the current position of /// the enumerator. /// The enumerator is /// positioned before the first element of the collection or after the /// last element or the collection was modified after the enumerator /// was created. object IEnumerator.Current { get { return Current; } } /// /// Advances the enumerator to the next element of the collection. /// /// /// true if the enumerator was successfully advanced to the next element; /// false if the enumerator has passed the end of the collection. /// /// The collection was /// modified after the enumerator was created. public abstract bool MoveNext(); /// /// Sets the enumerator to its initial position, which is before the /// first element in the collection. /// /// The collection was /// modified after the enumerator was created. public virtual void Reset() { ResetInternal(); } /// /// The inclusive node to start from (it will become the first value of /// . /// protected T Start { get; set; } /// /// True if this has started iterating /// ( has been called). /// protected bool Started { get; set; } /// /// The method that retrieves the from an /// instance of type . Typically, it will look /// something like this (using a lambda expression): /// /// foobar => foobar.Children.GetEnumerator(); /// /// protected Func> GetChildEnumerator; /// /// Represents the various levels of a tree (imagine the tree as a pyramid /// with the one node at the top and child nodes at each story in the /// pyramid). This list holds the enumerators we are currently enumerating /// through. /// protected LinkedList> EnumeratorLevels { get; set; } /// /// This member is called in both the constructor and the /// method. It was created to prevent a virtual /// method call being made in the constructor. /// void ResetInternal() { EnumeratorLevels.Clear(); Started = false; } /// /// The backing field to . /// T _current; } }