C# enumerator

Posted by JAB Creations on Sun, 30 Jan 2022 10:15:16 +0100

Summary:

1. Enumerators are like "cursors" or "Bookmarks" in a sequence. There can be multiple "Bookmarks". Moving any one of them can enumerate collections without affecting each other with other enumerators. Used to traverse data structures (watch chains, arrays, collection class members, etc.).

2. You can use foreach to traverse the enumerator. Foreach is used to traverse duck types Click to view the detailed usage of foreach

What is an enumerator

The class that implements the IEnumerator interface is the enumerator.

Enumerator function

Enumerators are like "cursors" or "Bookmarks" in a sequence. There can be multiple "Bookmarks". Moving any one of them can enumerate collections without affecting each other with other enumerators. Used to traverse data structures (watch chains, arrays, collection class members, etc.).

Principle of enumerator

 

 

 

 

 

 

IEnumerator interface

The enumerator that implements the IEnumerator interface contains three members of public type: Current, MoveNext() and Reset().

Implemented in the IEnumerator nested class so that multiple enumerators can be created.

Other data structures such as arrays, watch chains, and can be used inside the enumerator. The following example uses an array

Current: returns the currently processed element.

  • It is a read-only property.
  • It returns a reference of type object, so it can return any type.

MoveNext(): a method that moves the enumerator position forward to the next item in the collection.

  • It also returns a boolean indicating whether the new position is a valid position or has passed the end of the sequence.
  • If the new location is valid.
  • If the new location is invalid (for example, the current location reaches the tail), the method returns false.
  • The original location of the enumerator is before the first item in the sequence, so MoveNext must be called before the first use of Current.
    int[] i = {1,1,1,2 };
    var  ie= i.GetEnumerator();
    //Incorrect writing because the enumerator is before the first element in the collection and immediately after the creation of the enumerator. MoveNext Before reading the value of, you must call to move the enumerator forward to the first element of the collection Current . 
    Console.Write(ie.Current);
    ie.MoveNext();

     

Reset(): method to reset the position to the original state. (the Reset method usually throws NotImplementedException, so it should not be called. If you need to restart enumeration, just create a new enumerator.)

Implementation of enumerator

This method is not good. You cannot create multiple enumeration instances.

using System;
using System.Collections;
namespace ConsoleEnum
{
    public class cars : IEnumerator,IEnumerable
    {
       private car[] carlist;
       int position = -1;
       //Create internal array in constructor.
       public cars()
       {
           carlist= new car[6]
           {
               new car("Ford",1992),
               new car("Fiat",1988),
               new car("Buick",1932),
               new car("Ford",1932),
               new car("Dodge",1999),
               new car("Honda",1977)
           };
       }
       //IEnumerator and IEnumerable require these methods.
       public IEnumerator GetEnumerator()
       {
           return (IEnumerator)this;
       }
       //IEnumerator
       public bool MoveNext()
       {
           position++;
           return (position < carlist.Length);
       }
       //IEnumerable
       public void Reset()
       {
           position = -1;
       }
       //IEnumerable
       public object Current
       {
           get { return carlist[position];}
       }
    }
  }

The examples in this article are as simple as possible (so use arrays instead of other data deconstructions (single table chains)) to better explain the use of these interfaces. However, the case also reflects a problem.

If the method is accessed by multiple threads, it will cause this instance, because MoveNext() is shared. It will lead to disorder.

To make your code more reliable and ensure that it uses current best practice guidelines, modify the code as follows:

Best practices

  • Separate the functions of IEnumerable and IEnumerator interfaces. The collection class itself implements IEnumerable, and enumerators (classes that inherit the IEnumerator interface) are nested inside the collection class, so that multiple enumerators can be created.
  • Enumerators are like "cursors" or "Bookmarks" in a sequence. There can be multiple "Bookmarks". Moving any one of them can enumerate collections without affecting each other with other enumerators.
  • Provide Current exception handling ienumeror for the method. If the contents of the collection change, the reset method is called. Therefore, if the Current enumerator fails, you will receive an IndexOutOfRangeException. Other conditions may also cause this exception. Therefore, try Catch block to catch this exception and throw an InvalidOperationException exception.
using System;
using System.Collections;
namespace ConsoleEnum
{
    public class cars : IEnumerable
    {
        private car[] carlist;
  
        //Create internal array in constructor.
        public cars()
        {
            carlist= new car[6]
            {
                new car("Ford",1992),
                new car("Fiat",1988),
                new car("Buick",1932),
                new car("Ford",1932),
                new car("Dodge",1999),
                new car("Honda",1977)
            };
        }
        //private enumerator class
        private class  MyEnumerator:IEnumerator
        {
            public car[] carlist;
            int position = -1;

            //constructor
            public MyEnumerator(car[] list)
            {
                carlist=list;
            }
            private IEnumerator getEnumerator()
            {
                return (IEnumerator)this;
            }
            //IEnumerator
            public bool MoveNext()
            {
                position++;
                return (position < carlist.Length);
            }
            //IEnumerator
            public void Reset()
            {
                position = -1;
            }
            //IEnumerator
            public object Current
            {
                get
                {
                    try
                    {
                        return carlist[position];
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
        }  //end nested class
      public IEnumerator GetEnumerator()
      {
          return new MyEnumerator(carlist);
      }
    }
}

 

 

Application of enumerator in collection

First, the collection must inherit the IEnumerable interface, which tells others that it can enumerate, and its internal enumerator has been implemented. Others can obtain enumerator through GetEnumerator() method provided by IEnumerable interface. Then access the collection members through the movetext of the enumerator.

Second, then you need to put an enumerator inside the collection class (nesting a class with a real ienumeror interface). However, the collection of its own Unidirectional linked list Pass in the enumerator, which is like a cursor on a linked list.

Third, others can get the enumerator of the collection class by calling the GetEnumerator() method of the collection class. Access the collection sequentially through the enumerator.

 

What are the classes that implement the IEnumerable interface:

Arrays, collection classes, and so on

 

Topics: C#