C#中的foreach语句可用于循环遍历某个集合中的元素,而所有的只要支持了IEnumerable或IEnumerable<T>泛型接口的类型都是可以
用foreach遍历的。其具体的遍历实现过程就是利用C#中的迭代器中的方法来按照特定顺序遍历的。在.NET中IEnumerator和IEnumerator<T>
就是对迭代器的抽象,如果要自定义的类型也支持foreach循环则首先须要声明该类支持IEnumerable或IEnumerable<T>接口,然后再去实现自己
的支持了IEnumerator<T>的迭代器类型;唉,先看代码吧!
---------YYC
For Example:
// 实现了IEnumerable<T>泛型接口的类
using System; using System.Collections.Generic; using System.Collections; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Pra6 { public enum PhoneType { 家庭电话,办公电话,手机,小灵通,传真 } 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 new MyEnumerator<string>(phones); } IEnumerator IEnumerable.GetEnumerator()//返回迭代器,由于IEnumerable<T>接口也继承了IEnumerable接口所以出于兼容性考虑,最后也要实现该方法,但内容可//以和上面的代码一样 { return this.GetEnumerator(); } } }
// 实现了IEnumerator<T>的迭代器类型
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 {//返回当前数据 get { return array[current]; } } public MyEnumerator(T[] array) { this.array = array; this.current = -1; } public bool MoveNext()//使迭代器移向下一项 { if (++current == array.Length) return false ; return true; } object IEnumerator.Current//返回当前的数据,同样也是出于兼容性的考虑 { get { return array [current];} } public void Reset()//重设迭代器,以便重新开始遍历 { current = -1; } void IDisposable.Dispose() { } } }
//调用过程
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.办公电话] = "111"; ph[PhoneType.传真] = "222"; ph[PhoneType.家庭电话] = "333"; ph[PhoneType.手机] = "444"; ph[PhoneType.小灵通] = "555"; textBox1.Text = null; //方法一:调用foreach实现 foreach(string s in ph) { textBox1.Text += s+" "; } //调用迭代器实现遍历。 IEnumerator<string> iter = ph.GetEnumerator(); while(iter.MoveNext()) { textBox1.Text += iter.Current + " "; } } } }
其实,在.NET的中间语言是并不支持foreach语句的,而是C#的编译器可以将程序中的foreach语句转换成
对迭代器操作的while或for语句的循环遍历,例如:上面的:
foreach(string s in ph)
{
textBox1.Text += s+" ";
}
其真实的执行代码就是
IEnumerator<string> iter = ph.GetEnumerator();
while(iter.MoveNext())
{
textBox1.Text += iter.Current + " ";
}
所以当我们懂了这个实现原理后我们也是可以去定义我们自己的可以支持foreach的类型了,
但是需要值得一提的是并非我们每次都需要去显示的自己定义我们的迭代器类型,C#语言本身
一大特色就是快速开发吗,这是因为C#中为迭代器模式提供了一种简化实现方式,即使用yield returne语句。
例如:将上面的Phones类中的GetEnumerator()直接改为下面的方式,不用再去定义迭代器类型,就能直接
使用foreach语句:
public IEnumerator<string> GetEnumerator() { for (int i = 0; i < 5;i++ ) { if (phones[i]!=null) yield return phones[i]; } }