平时工作中我们经常用foreach来迭代一个集合。比如
1 foreach (Student student in myClass)
2 {
3 Console.WriteLine(student);
4 }
5
基本所有的集合都能够foreach,但是必须要实现IEnumerable接口。IEnumerable接口很简单,就只有一个IEnumerator GetEnumerator() 方法。看这个方法的定义就知道,仅仅是公开了另一个接口IEnumerator。而IEnumerator才是真正的支持一个集合的迭代。IEnumerator有1个属性和2个方法。
public object Current;
public void Reset();
public bool MoveNext();
只允许读取集合的数据,而不允许修改。为了详细的讲解,我们来写一个简单的例子,就会一目了然。
首先我们创建一个学生类Student如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace IenumerableDemo
7 {
8 public class Student
9 {
10 #region 私有变量
11
12 private readonly string _id;
13 private string _firstname;
14 private string _lastname;
15
16 #endregion
17 #region 属性
18 public string ID { get { return _id; } }
19
20 public string FirstName { get { return _firstname; } set { _firstname = value; } }
21
22 public string LastName { get { return _lastname; } set { _lastname = value; } }
23
24
25 #endregion
26
27 #region 构造函数
28
29 public Student(string id, string firstname, string lastname)
30 {
31 this._id = id;
32
33 this._firstname = firstname;
34
35 this._lastname = lastname;
36 }
37
38 #endregion
39 #region 重写基类object方法
40
41 public override string ToString()
42 {
43 return string.Format("{0} {1},ID:{2}", _firstname, _lastname, _id);
44 }
45
46 public override bool Equals(object obj)
47 {
48 if (obj == null) return false;
49 if (Object.ReferenceEquals(this, obj)) return true;
50 if (this.GetType() != obj.GetType()) return false;
51
52 Student objstudent = (Student)obj;
53 if (_id.Equals(objstudent._id)) return true;
54
55 return false;
56 }
57
58 public override int GetHashCode()
59 {
60 return _id.GetHashCode();
61 }
62 #endregion
63
64 }
65 }
66
67
接下来我们定义一个ClassList类来承载学生。让我们先忘记Ienmerable。这个类包含一个ArrayList字段_student,在构造函数中模拟3个学生。_student是私有的,不对外公开的。
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 public class ClassList
10 {
11
12 #region private Members
13
14 private readonly string _id;
15
16 private ArrayList _students;
17
18 #endregion
19
20 #region Properties
21 public string ID { get { return _id; } }
22 #endregion
23
24 #region Constructors
25
26 public ClassList(string id)
27 {
28
29 this._id = id;
30 _students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };
31
32 }
33
34 #endregion
35
36
37 }
38 }
为了让对象支持foreach 迭代,ClassList类需要实现IEnumerable。因为我们的student是存在ArrayList对象里的,而ArrayList类已经实现了IEnumerable,我们就可以使用ArrayList类的Ienumerable。
1 public IEnumerator GetEnumerator()
2 {
3
4 return (_students as IEnumerable).GetEnumerator();
5
6 }
最终的代码贴一下:
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 public class ClassList:IEnumerable
10 {
11
12 #region private Members
13
14 private readonly string _id;
15
16 private ArrayList _students;
17
18 #endregion
19
20 #region Properties
21 public string ID { get { return _id; } }
22 #endregion
23
24 #region Constructors
25
26 public ClassList(string id)
27 {
28
29 this._id = id;
30 _students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };
31
32 }
33
34 #endregion
35
36 public IEnumerator GetEnumerator()
37 {
38
39 return (_students as IEnumerable).GetEnumerator();
40
41 }
42 }
43 }
然后我们调用看看使用ArrayList的Ienumerable效果:
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 ClassList myClass = new ClassList("History 204");
14
15
16 foreach (Student student in myClass)
17
18 Console.WriteLine(student);
19
20
21 Console.ReadLine();
22 }
23
24
25 }
26
27
28 }
看来还是实现了效果。那么接下来我们看看自定义实现IEnumerable。实现IEnumerable其实只要实现IEnumerator接口就可以了。
我们创建我们自己的一个自定义类ClassEnumerator 来实现IEnumerator来完成和上面相同的结果。这个类基本上就只是通过_students的索引来进行迭代,Reset()方法就是把索引设置为-1.Current属性来获取当前的student,MoveNext()来跳到Current的下一个数据,并返回一个boolean来表示是否到了集合最后。
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 public class ClassEnumerator : IEnumerator
10 {
11
12 private ClassList _classList;
13
14 private int _index;
15
16 public ClassEnumerator(ClassList classList)
17 {
18 this._classList = classList;
19
20 _index = -1;
21 }
22
23 #region IEnumerator Members
24
25 public void Reset()
26 {
27 this._index = -1;
28 }
29
30 public object Current
31 {
32 get { return _classList.Students[_index]; }
33 }
34
35 public bool MoveNext()
36 {
37 _index++;
38 if (_index >= _classList.Students.Count)
39 return false;
40 else
41 return true;
42
43 }
44 #endregion
45
46 }
47 }
最后修改我们的ClassLst类:
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 public class ClassList : IEnumerable
10 {
11
12 #region private Members
13
14 private readonly string _id;
15
16 private ArrayList _students;
17
18 #endregion
19
20 #region Properties
21 public string ID { get { return _id; } }
22
23 public ArrayList Students { get { return _students; } }
24 #endregion
25
26 #region Constructors
27
28 public ClassList(string id)
29 {
30
31 this._id = id;
32 _students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };
33
34 }
35
36 #endregion
37
38 public IEnumerator GetEnumerator()
39 {
40
41 return (IEnumerator)new ClassEnumerator(this);
42
43 }
44 }
45 }
可已看到还是相当简单的。运行结果和上面是一样的。
下来看看 foreach怎么工作。
其实foreach只是语法糖,最终会被CLR翻译成
1 IEnumerator enumerator = myClass.GetEnumerator();
2 while (enumerator.MoveNext())
3 {
4 Console.WriteLine((Student)enumerator.Current);
5
6 }
我们可以把foreach 换成这样试一下,结果是一样滴。
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 ClassList myClass = new ClassList("History 204");
14
15
16 //foreach (Student student in myClass)
17
18 // Console.WriteLine(student);
19
20
21 IEnumerator enumerator = myClass.GetEnumerator();
22 while (enumerator.MoveNext())
23 {
24 Console.WriteLine((Student)enumerator.Current);
25
26 }
27
28 Console.ReadLine();
29 }
30
31
32 }
33
34
35 }
编程是个人爱好
平时工作中我们经常用foreach来迭代一个集合。比如
1 foreach (Student student in myClass)
2 {
3 Console.WriteLine(student);
4 }
5
基本所有的集合都能够foreach,但是必须要实现IEnumerable接口。IEnumerable接口很简单,就只有一个IEnumerator GetEnumerator() 方法。看这个方法的定义就知道,仅仅是公开了另一个接口IEnumerator。而IEnumerator才是真正的支持一个集合的迭代。IEnumerator有1个属性和2个方法。
public object Current;
public void Reset();
public bool MoveNext();
只允许读取集合的数据,而不允许修改。为了详细的讲解,我们来写一个简单的例子,就会一目了然。
首先我们创建一个学生类Student如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace IenumerableDemo
7 {
8 public class Student
9 {
10 #region 私有变量
11
12 private readonly string _id;
13 private string _firstname;
14 private string _lastname;
15
16 #endregion
17 #region 属性
18 public string ID { get { return _id; } }
19
20 public string FirstName { get { return _firstname; } set { _firstname = value; } }
21
22 public string LastName { get { return _lastname; } set { _lastname = value; } }
23
24
25 #endregion
26
27 #region 构造函数
28
29 public Student(string id, string firstname, string lastname)
30 {
31 this._id = id;
32
33 this._firstname = firstname;
34
35 this._lastname = lastname;
36 }
37
38 #endregion
39 #region 重写基类object方法
40
41 public override string ToString()
42 {
43 return string.Format("{0} {1},ID:{2}", _firstname, _lastname, _id);
44 }
45
46 public override bool Equals(object obj)
47 {
48 if (obj == null) return false;
49 if (Object.ReferenceEquals(this, obj)) return true;
50 if (this.GetType() != obj.GetType()) return false;
51
52 Student objstudent = (Student)obj;
53 if (_id.Equals(objstudent._id)) return true;
54
55 return false;
56 }
57
58 public override int GetHashCode()
59 {
60 return _id.GetHashCode();
61 }
62 #endregion
63
64 }
65 }
66
67
接下来我们定义一个ClassList类来承载学生。让我们先忘记Ienmerable。这个类包含一个ArrayList字段_student,在构造函数中模拟3个学生。_student是私有的,不对外公开的。
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 public class ClassList
10 {
11
12 #region private Members
13
14 private readonly string _id;
15
16 private ArrayList _students;
17
18 #endregion
19
20 #region Properties
21 public string ID { get { return _id; } }
22 #endregion
23
24 #region Constructors
25
26 public ClassList(string id)
27 {
28
29 this._id = id;
30 _students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };
31
32 }
33
34 #endregion
35
36
37 }
38 }
为了让对象支持foreach 迭代,ClassList类需要实现IEnumerable。因为我们的student是存在ArrayList对象里的,而ArrayList类已经实现了IEnumerable,我们就可以使用ArrayList类的Ienumerable。
1 public IEnumerator GetEnumerator()
2 {
3
4 return (_students as IEnumerable).GetEnumerator();
5
6 }
最终的代码贴一下:
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 public class ClassList:IEnumerable
10 {
11
12 #region private Members
13
14 private readonly string _id;
15
16 private ArrayList _students;
17
18 #endregion
19
20 #region Properties
21 public string ID { get { return _id; } }
22 #endregion
23
24 #region Constructors
25
26 public ClassList(string id)
27 {
28
29 this._id = id;
30 _students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };
31
32 }
33
34 #endregion
35
36 public IEnumerator GetEnumerator()
37 {
38
39 return (_students as IEnumerable).GetEnumerator();
40
41 }
42 }
43 }
然后我们调用看看使用ArrayList的Ienumerable效果:
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 ClassList myClass = new ClassList("History 204");
14
15
16 foreach (Student student in myClass)
17
18 Console.WriteLine(student);
19
20
21 Console.ReadLine();
22 }
23
24
25 }
26
27
28 }
看来还是实现了效果。那么接下来我们看看自定义实现IEnumerable。实现IEnumerable其实只要实现IEnumerator接口就可以了。
我们创建我们自己的一个自定义类ClassEnumerator 来实现IEnumerator来完成和上面相同的结果。这个类基本上就只是通过_students的索引来进行迭代,Reset()方法就是把索引设置为-1.Current属性来获取当前的student,MoveNext()来跳到Current的下一个数据,并返回一个boolean来表示是否到了集合最后。
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 public class ClassEnumerator : IEnumerator
10 {
11
12 private ClassList _classList;
13
14 private int _index;
15
16 public ClassEnumerator(ClassList classList)
17 {
18 this._classList = classList;
19
20 _index = -1;
21 }
22
23 #region IEnumerator Members
24
25 public void Reset()
26 {
27 this._index = -1;
28 }
29
30 public object Current
31 {
32 get { return _classList.Students[_index]; }
33 }
34
35 public bool MoveNext()
36 {
37 _index++;
38 if (_index >= _classList.Students.Count)
39 return false;
40 else
41 return true;
42
43 }
44 #endregion
45
46 }
47 }
最后修改我们的ClassLst类:
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 public class ClassList : IEnumerable
10 {
11
12 #region private Members
13
14 private readonly string _id;
15
16 private ArrayList _students;
17
18 #endregion
19
20 #region Properties
21 public string ID { get { return _id; } }
22
23 public ArrayList Students { get { return _students; } }
24 #endregion
25
26 #region Constructors
27
28 public ClassList(string id)
29 {
30
31 this._id = id;
32 _students = new ArrayList() { new Student("12345", "John", "Smith"), new Student("09876", "Jane", "Doe"), new Student("76403", "Bob", "Johnson") };
33
34 }
35
36 #endregion
37
38 public IEnumerator GetEnumerator()
39 {
40
41 return (IEnumerator)new ClassEnumerator(this);
42
43 }
44 }
45 }
可已看到还是相当简单的。运行结果和上面是一样的。
下来看看 foreach怎么工作。
其实foreach只是语法糖,最终会被CLR翻译成
1 IEnumerator enumerator = myClass.GetEnumerator();
2 while (enumerator.MoveNext())
3 {
4 Console.WriteLine((Student)enumerator.Current);
5
6 }
我们可以把foreach 换成这样试一下,结果是一样滴。
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6
7 namespace IenumerableDemo
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 ClassList myClass = new ClassList("History 204");
14
15
16 //foreach (Student student in myClass)
17
18 // Console.WriteLine(student);
19
20
21 IEnumerator enumerator = myClass.GetEnumerator();
22 while (enumerator.MoveNext())
23 {
24 Console.WriteLine((Student)enumerator.Current);
25
26 }
27
28 Console.ReadLine();
29 }
30
31
32 }
33
34
35 }