using System; using System.Collections; using System.Collections.Generic; namespace Chernobyl.Collections.Generic { /// /// An that iterates through instances of types /// that are structured like a linked list. i.e., the type contains an /// instance to another instance of the same type. For example: /// /// public class Foobar /// { /// public Foobar NextFoo { get; set; } /// } /// /// /// The type that contains an instance of it's /// own type (a class that acts as a node in a linked list). public class LinkedEnumerator : IEnumerator { /// /// Initializes a new instance of the /// class. /// /// The inclusive node to start from (it will /// become the first value of . /// A method that returns the next item for the /// current instance. The current instance is passed into the method as /// the first argument and the second argument is for returning the next /// instance. False is to be returned if there is no next item, true if /// the next item set on the second parameter is a valid instance. public LinkedEnumerator(T start, NextItem getNextItem) { Start = start; GetNextItem = getNextItem; Reset(); } /// /// 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. public T Current { get { if (Started == false) throw new InvalidOperationException("The enumerator is " + "positioned before the first element of the collection " + "Make sure the MoveNext() method has been called. "); if (Finished == true) throw new InvalidOperationException("The enumerator is " + "positioned after the last element of the collection " + "Make sure to call Reset() to before restarting the iteration. "); return _current; } private set { _current = value; } } /// /// Performs application-defined tasks associated with freeing, releasing, /// or resetting unmanaged resources. /// public void Dispose() { /* Does nothing */ } /// /// 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. 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 bool MoveNext() { bool result = false; if (Started == false) { result = Started = true; Current = Start; } else { // GetNextItem will return false if we are finished, true if otherwise Finished = !GetNextItem(Current, out _current); result = !Finished; } return result; } /// /// 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 void Reset() { Current = Start; Started = false; Finished = false; } /// /// Represents a method that is used to retrieve the next item in a /// linked set of instances. /// /// The current item that was enumerated over. /// The instance that is to take the result of the /// next item to enumerate through. /// False if there is no next item, true if the next item set /// on is valid. public delegate bool NextItem(T current, out T next); /// /// A method that returns the next item for the current instance. The /// current instance is passed into the method as the first argument and /// the second argument is for returning the next instance. False is to /// be returned if there is no next item, true if the next item set /// on the second parameter is a valid instance. /// NextItem GetNextItem { get; set; } /// /// The inclusive node to start from (it will become the first value of /// . /// T Start { get; set; } /// /// True if this has started iterating /// ( has been called), false if we haven't /// started. /// protected bool Started { get; set; } /// /// True if the end of the resource processing chain has been reached, /// false if otherwise. /// bool Finished { get; set; } /// /// Backing field to . /// T _current; } }