C#的集合功能可谓十分强大,这里着重探讨集合中非常重要的两个接口:IEnumerable<T>和IEnumerator<T>.
首先查看如下代码:
2 {
3 public int _id;
4 public string _name;
5
6 public Student(int id, string name)
7 {
8 this._id = id;
9 this._name = name;
10 }
11
12 public override string ToString()
13 {
14 return string.Format("{0}-{1}", _id, _name);
15 }
16 }
17
18 class Program
19 {
20 public static void Main()
21 {
22 List<Student> students = new List<Student>()
23 {
24 new Student(1, "Tomas"), new Student(2, "Lily")
25 };
26
27 foreach (Student student in students)
28 {
29 Console.WriteLine(student);
30 }
31 }
32 }
这里我首先定义一个学生类,然后在Main方法中定义一个集合, 这里用集合初始化器向集合中添加内容,最后在遍历集合中的内容。我们看到C#中遍历集合的内容是如此方便。可以说C#中对如何访问集合内的元素进行彻底的封装,我们不必了解集合内部的结构,就能轻松访问集合的内容,然后借助查询表达式或者查询运算符可以进行查询等一系列方便的操作,这里不再赘述。
但是C#内部究竟是怎么访问集合中的数据的呢?这就要提到我们上面提到的接口IEnumerable<T> ,所有集合都实现了该接口,或者更精确的说所有想要被foreach遍历的集合必须实现这个接口。这个接口十分简单,实现该接口的类只要实现GetEnumerator()方法就可以了。如下所示:
2 public interface IEnumerable<out T> : IEnumerable
3 {
4 IEnumerator<T> GetEnumerator();
5 }
这里就有涉及到我提到的另一个接口IEnumerator<T>,那这个接口又是干什么的呢?使用java的人都知道java中遍历集合通常使用Iterator,也就是迭代器,你可以在不知道集合内部结构的前提下,轻松访问集合的数据,也就是设计模式中的迭代器模式。C#中IEnumerator就是迭代器,其内部结构如下所示:
2 [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")]
3 public interface IEnumerator
4 {
5 object Current { get; }
6
7 bool MoveNext();
8
9 void Reset();
10 }
IEnumerator接口的Current属性用于获取当前对象,MoveNext()则告诉调用者是否还有下一个元素。
我们回到本文的第一个代码,当我们遍历集合的时候,由于该集合实现了IEnumerable<T>接口,所以foreach会调用IEnumerable的GetEnumerator()方法,返回一个迭代器对象,然后利用迭代器就可以访问集合中的数据了,当然所有这一切都是隐式调用的。如下所示:
2
3 while (enumerator.MoveNext())
4 {
5 Console.WriteLine(enumerator.Current);
6 }
在java中是不是就是这样访问集合元素的啊。