Introduction to IEnumerable in C and simple implementation examples

  • 2021-01-14 06:27:22
  • OfStack

The interface IEnumerable says so on MSDN, which is a public enumerator that supports simple iteration over a non-generic collection. In other words, all array traversal comes from IEnumerable, so we can use this feature to define a common method that traverses a string.

Let's post code first.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
 
namespace mycs
{
  class Program
  {
    static void Main(string[] args)
    {
      charlist mycharlist = new charlist("hello world");
      foreach (var c in mycharlist)
      {
        Console.Write(c);
      }
     Console.ReadLine();
    }
  }
 
  class charlist : IEnumerable
  {
    public string TargetStr { get; set; }
 
    public charlist(string str)
    {
      this.TargetStr = str;
    }
    public IEnumerator GetEnumerator()
    {
      //c# 1.0
      return new CharIterator(this.TargetStr);
      //c# 2.0
      /*
      for (int index = this.TargetStr.Length; index > 0;index-- )
      {
        yield return this.TargetStr[index - 1];
      }
       */
    }
  }
  class CharIterator : IEnumerator
  {
    public string TargetStr { get; set; }
    public int position { get; set; }
 
    public CharIterator(string targetStr)
    {
      this.TargetStr = targetStr;
      this.position = this.TargetStr.Length;
    }
    public object Current
    {
      get
      {
        if (this.position==-1||this.position==this.TargetStr.Length)
        {
          throw new InvalidOperationException();
        }
        return this.TargetStr[this.position];
      }
    }
    public bool MoveNext()
    {
      if (this.position!=-1)
      {
        this.position--;
      }
      return this.position > -1;
    }
    public void Reset()
    {
      this.position = this.TargetStr.Length;
    }
  }
}


In the example c# 1.0 above, CharIterator is the implementation of an iterator. The position field stores the current iteration position, the Current attribute is used to retrieve the element of the current iteration position, and the MoveNext method is used to update the iteration position and see if the next iteration position is valid.

When we step through VS for the following statement:


foreach (var c in charList)

The code executes first to the charList of the foreach statement to get an instance of the iterator CharIterator, then to the in it calls the MoveNext method of the iterator, and finally to the variable c it gets the value of the property of the iterator Current. When the previous steps are complete, a new loop is started, calling the MoveNext method to get the value of the Current attribute.

As you can see from the iterator code in C# 1.0, implementing one iterator requires implementing the IEnumerator interface, and then implementing the MoveNext, Reset methods, and Current properties in the IEnumerator interface.

yield statements can be used directly in C# 2.0 to simplify the implementation of iterators.

For example, the section of the public IEnumerator GetEnumerator() method commented out above.
As you can see from the above code, we can replace the entire CharIterator class by using the yield return statement.

yield The return statement tells the compiler to implement an iterator block. If the return type of the GetEnumerator method is a non-generic interface, then the generated type of the iterator block (yield type) is object, otherwise it is the type parameter of the generic interface.


Related articles: