Search code examples
c#foreachenumeratorcircular-list

how do I create GetEnumerator of my circular list?


I have to create my own circular list, I using the generic one.

first i create the Node<D> class which represents the data and the next of the element

      private class Node<D> {
            public D info;
            public Node<D> next;

            public Node() {

            }

            public Node(D p) {
                info = p;
            }
        } 

To create the circular list, I create the circularList<T> class. this class using Node<> as item of the element.

Here is the CircularList<T> class

class CircularList<T> : IEnumerable<T> {
    public Node<T> start;
    public Node<T> rear;
    public int count = 0;
    public CircularList(T firstItem) {
        start = new Node<T>(firstItem);
        rear = start;
        rear.next = start;
    }

    public void Insert(T newItem) {
        //Inserting code here
    }

    public void Update(T oldItem, T newItem) {
        //Updating code is here
    }

    public void Delete(T theItem) {
        //deleting code is here
    }


}

when I start to loop using foreach

foreach(string item in CircularList<string>){

}

I got an error says that the circularlist class needs GetEnumerator().

Actually I can loop all of my circular list, but I am using do-while and I need Node<T> to start the loop. but I don't want using Node and do-while.

How do I create the GetEnumerator()?

Any help appreciated. :)

Thank you

Note: I really-really don't understand about IEnumerable and those things, please go easy with the example and explanation.


Solution

  • You need to implement GetEnumerator() method from IEnumerable for the foreach to work.

    Use something like following:

    public class CircularList<T> : IEnumerable<T>
    {
        private List<T> mylist = new List<T>();
    
        public T this[int index]
        {
            get
            {
                return this.mylist[index];
            }
            set
            {
                this.mylist.Insert(index, value);
            }
        }
    
        public IEnumerator<T> GetEnumerator()
        {
            return this.mylist.GetEnumerator();
        }
    
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
    

    mylist maintains the list of type T which you would insert, update and delete.

    EDIT

    myList is just the backing storage of your "custom" list. As long as you are implementing your underlying functionality correctly, myList could be array, arraylist and so on. For simplicity, I've used List<T> here which already implements the interface IEnumerable<T> and IEnumerator<T>( notice IEnumera**tor** not IEnumerable).

    See this answer for more details on the difference between IEnumerator and IEnumerable

    Moreover, The foreach statement hides the complexity of the enumerators. See IEnumerator for more details.

    The compiler turns the foreach into something like this:

    CircularList<string> testList=new CircularList<string>();
    
    IEnumerator testEnumerator= testList.GetEnumerator();
    while (testEnumerator.MoveNext())
    {
      string yourForEachIteratorVariable = (string)testEnumerator.Current
       ...
    }
    

    Please note that the codes here are only for the illustration purposes. You could/should modify to make it more flexible and "performant" according to your need/requirement.

    And for linked list, you don't need a backing List<T>, you could simply add/insert on your head node and implement GetEnumerator() something like below:

     public IEnumerator<T> GetEnumerator()
      {
       var node = start;
       while(node != null)
       {
        yield return node.info;
        node = node.next;
     }
    }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
     return GetEnumerator();
    }