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;
}
}