C # Analysis of IEnumerable and IEnumerator interfaces,
It is necessary to review the basic knowledge and deepen understanding and memory.
Foreach is often used to access the set cyclically. it traverses the containers that implement the IEnumerable interface. I am also confused about the IEnumerable and IEnumerator interfaces. According to the official explanation, IEnumerable is the enumeration interface, IEnumerator is an iterator interface, which is literally similar. Let's analyze it one by one.
IEnumerable Interface
public interface IEnumerable{ IEnumerator GetEnumerator();}
The class inheriting the IEnumerable interface needs to implement the exposed GetEnumerator () method and return an IEnumerator interface object. It seems that IEnumerator is actually doing things. F12 will take a look at what IEnumerator has.
IEnumerator Interface
public interface IEnumerator{ object Current { get; } bool MoveNext(); void Reset();}
The IEnumerator interface has three items, one attribute is Current, and elements in the Current set are returned. The MoveNext () method is moved to the next one, and traversal is not always backward traversal. Reset (), literally Reset, this is easy to understand. Make a hypothesis: Since the IEnumerable interface returns the result implemented by the IEnumerator interface iterator, can I implement a custom container by inheriting only the IEnumerator iterator interface?
DefinePhoneClass
public class Phone { public string Name; public Phone(string name) { this.Name = name; }}
DefineMyEnumeratorIterator, and implements its interface IEnumerator
public class MyEnumerator : IEnumerator{ Phone[] p; int idx = -1; public MyEnumerator(Phone[] t) { p = t; } public object Current { get { if (idx == -1) return new IndexOutOfRangeException(); return p[idx]; } } public bool MoveNext() { idx++; return p.Length > idx; } public void Reset() { idx = -1; }}
class Program { static void Main(string[] args) {
show("-----------IEnumerator------------"); Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") }; MyEnumerator enumerator = new MyEnumerator(phones); while (enumerator.MoveNext()) { Phone p = enumerator.Current as Phone; show(p.Name); } Console.ReadKey(); } static void show(string i) { Console.WriteLine(i); } }
Result:
As expected, the IEnumerator interface is used to access a custom container cyclically. However, the original intention is to use Foreach for loop access and traversal. Well, you can only display the IEnumerable interface. Slightly rebuildPhoneClass:
public class Phone : IEnumerable { public string Name ; public Phone(string name) { this.Name = name; } Phone[] p; public Phone(Phone[] t) { p = t; } public IEnumerator GetEnumerator() { return new MyEnumerator(p); } }
static void Main(string[] args) { show("-----------IEnumerator------------"); Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") }; MyEnumerator enumerator = new MyEnumerator(phones); while (enumerator.MoveNext()) { Phone p = enumerator.Current as Phone; show(p.Name); } show("-----------IEnumerable------------"); Phone phoneList = new Phone(phones); foreach (Phone p in phoneList) { show(p.Name); } Console.ReadKey(); }
Result:
Success, and then expansion into a general containerPhonePackageTo inherit the generic IEnumerable <T> interface.
public class PhonePackage<T> : IEnumerable<T> { private List<T> dataList = null; public void Add(T t) { if (dataList == null) dataList = new List<T>(); dataList.Add(t); } public IEnumerator<T> GetEnumerator() { foreach (T t in dataList) { yield return t; } } IEnumerator IEnumerable.GetEnumerator() { foreach (T t in dataList) { yield return t; } } }
static void Main(string[] args) { show("-----------IEnumerator------------"); Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") }; MyEnumerator enumerator = new MyEnumerator(phones); while (enumerator.MoveNext()) { Phone p = enumerator.Current as Phone; show(p.Name); } show("-----------IEnumerable------------"); Phone phoneList = new Phone(phones); foreach (Phone p in phoneList) { show(p.Name); } show("-----------IEnumerable<T>------------"); PhonePackage<Phone> phonePackage = new PhonePackage<Phone>(); phonePackage.Add(new Phone("iPhone 7s")); phonePackage.Add(new Phone("iPhone 6s")); phonePackage.Add(new Phone("iPhone 5s")); foreach (Phone p in phonePackage) { show(p.Name); } Console.ReadKey(); } static void show(string i) { Console.WriteLine(i); }
Result:
The inumerator iterator interface is coorse, and yield is the syntactic sugar that simplifies traversal.
Reference List <T> source code: http://www.projky.com/dotnet/4.5.1/System/Collections/Generic/List.cs.html