Iterator Implementation Mechanism of foreach Statement in C#

Posted by alohatofu on Sun, 21 Jul 2019 12:06:01 +0200

Links to the original text: http://www.cnblogs.com/riasky/p/3481600.html

The foreach statement in C # can be used to iterate through elements in a collection, and all types that support IEnumerable or IEnumerable < T> generic interfaces can be used.

Traversal with foreach. Its specific traversal implementation process is to use the iterator method in C # to traverse in a specific order. In. NET, IEnumerator and IEnumerator<T>

This is the abstraction of iterators. If you want to customize a type that also supports foreach loops, you first need to declare that it supports IEnumerable or IEnumerable < T > interfaces, and then implement yourself.

Iterator types that support IEnumerator <T>; alas, look at the code first!


---------YYC

For Example:

 


// Classes that implement IEnumerable < T > generic interfaces

 

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pra6
{
    public enum PhoneType
    { 
     //Home phone, office phone, mobile phone, PHS, fax
    }

    class Phones : IEnumerable<string>
    {
        private string[] phones;
        private int count = 0;
        public int Count {
            get { return count; }
        }
        public string this[PhoneType type]
        {
            get { 
               return phones[(int)type];
            }
            set { 
              int index  =  (int)type;
              if (phones[index] == null && value != null)
              {
                  count++;
              }
              else
                  if (phones[index] != null && value == null)
                  {
                      count--;
                  }
              phones[index] = value;
            }
        }

        public Phones()
        {
            phones = new string[5];
        }
        public void CopyTo( Array array,int index)
        { 
          foreach(string s in phones )
          {
              if (s != null)
                  array.SetValue(s,index++);
          }
        }
      public   IEnumerator<string > GetEnumerator()//Return iterator
        {
            return new MyEnumerator<string>(phones);
        }
        IEnumerator IEnumerable.GetEnumerator()//Return to the iterator, because the IEnumerable < T > interface also inherits the IEnumerable interface, for compatibility reasons, and finally implement this method, but the content can be // or the same as the code above.
        {
            return this.GetEnumerator();
        }

    }
}

 

// The iterator type of IEnumerator < T> is implemented.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace Pra6
{
    class MyEnumerator<T>:IEnumerator<T>
    {
        private int current;
        internal T[] array;
        public T Current {//Return current data
            get { return array[current]; }
        }
        public MyEnumerator(T[] array)
        {
            this.array = array;
            this.current = -1;
        }
        public bool MoveNext()//Move the iterator to the next item
        {
            if (++current == array.Length)
                return false ;
            return true;
        }
        object IEnumerator.Current//Returning current data is also compatible
        { 
           get { return array [current];}
        }
        public void Reset()//Reset the iterator to restart traversal
        {
            current = -1;
        }
        void IDisposable.Dispose()
        { 
        
        }



    }
}


// Call procedure

 

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Pra6
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            LinkedList<string> aa = new LinkedList<string>();
            string a1 = "aa";
            string a2 = "bb";
            string a3 = "cc";
            string a4 = "dd";
            LinkedListNode<string> b1 = aa.AddFirst(a1);
            b1 =  aa.AddAfter(b1,a2);
            b1 = aa.AddAfter(b1, a3);
            aa.AddLast(a4);
            textBox1.Text = null ;
            foreach (string a in aa )
            {
                textBox1.Text += "   " + a;
            }
            b1 = b1.Next;
            b1 = b1.Next;
           
            textBox1.Text += b1.Value;

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void button2_Click(object sender, EventArgs e)
        {
            Phones ph = new Phones();
            ph[PhoneType.Office Telephone] = "111";
            ph[PhoneType.Fax] = "222";
            ph[PhoneType.Home phone] = "333";
            ph[PhoneType.Mobile phone] = "444";
            ph[PhoneType.PHS] = "555";
            textBox1.Text = null;
            //Method 1: Call foreach implementation
            foreach(string s in ph)
            {
                textBox1.Text += s+"   ";
            }

            //Call the iterator to implement traversal.
            IEnumerator<string> iter = ph.GetEnumerator();
            while(iter.MoveNext())
            {
                textBox1.Text += iter.Current + "   ";
            }
        }
    }
}


In fact, the intermediate language in. NET does not support foreach statements, but C # compiler can convert foreach statements into foreach statements in programs.

 

Loop traversal of while or for statements for iterator operations, such as:

foreach(string s in ph)
            {
                textBox1.Text += s+"   ";
            }

The actual execution code is

IEnumerator<string> iter = ph.GetEnumerator();
            while(iter.MoveNext())
            {
                textBox1.Text += iter.Current + "   ";
            }

So when we understand this implementation principle, we can also define our own type of support for foreach.

But it's worth mentioning that not every time we need to show ourselves defining our iterator type, the C# language itself.

A big feature is rapid development, because C # provides a simplified implementation of the iterator pattern, even with yield return statements.

For example, change GetEnumerator() in the above Phones class directly to the following way, without defining the iterator type, you can directly

Use the foreach statement:

 

public IEnumerator<string> GetEnumerator()
      {
          for (int i = 0; i < 5;i++ )
          {
              if (phones[i]!=null)
                  yield return phones[i];
          }
      }

 

 

 



 





Reprinted at: https://www.cnblogs.com/riasky/p/3481600.html

Topics: Mobile Windows