一、IEnumerable接口
IEnumerable接口可以暴露一个Celltions的元素的迭代器,它只含有一个方法GetEnumerator,这个方法返回一个IEnumerator对象,而通过这个IEnumerator对象,我们就可以遍历整个Celltions中的元素。
二、代码示例
下面的代码,演示如何继承IEnumerable接口和IEnumerator接口,并通过继承IEnumerator实现用foreach遍历IEnumerator的派生类。首先我们先创建一个自定义的类对象Person用于作为集合对象的元素:
class Person
{
public Person(stringname)
{
this.name = name;
}
public string name;
}
接下来定义一个Person类的集合对象People,需要继承自IEnumerable接口,这个对象中必须实现GetEnumerator方法,我们在这个方法中返回一个IEnumerator的派生类PeopleEnum,而在这个派生类中将对需要遍历的People类对象进行封装,从而实现其遍历。
class People : IEnumerable
{
private Person[]_people;
public People(Person[]pArray)
{
_people = new Person[pArray.Length];
for (int i = 0; i< pArray.Length;i++)
{
_people[i] = pArray[i];
}
}
//实现GetEnumerator方法
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public PeopleEnum GetEnumerator()
{
return new PeopleEnum (_people);
}
}
接下来我们还需要实现对GetEnumerator的继承,定义PeopleEnum 类:
class PeopleEnum : IEnumerator
{
public Person[]_people;
int position = -1;
public PeopleEnum(Person[]list)
{
_people = list;
}
public boolMoveNext()
{
position++;
return position < _people.Length;
}
public void Reset()
{
position = -1;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public PersonCurrent
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw newInvalidOperationException();
}
}
}
}
可以看到,我们定义的PeopleEnum中position表示指向当前集合元素的索引,而我们分别实现了MoveNext()、Reset()两个方法和Current属性。Current获取当前索引指向的集合元素,而MoveNext()将索引向后移动一位,Reset()将索引回到起始状态。
经过了上面的实现,我们就可以直接用foreach迭代遍历People对象了:
Person[] peopleArray = newPerson[3]
{
new Person("张?三¨y"),
new Person("李¤?四?"),
new Person("王ª?五?"),
};
People people = newPeople(peopleArray) { };
foreach (var va in people)
{
Console.WriteLine(va.name);
}
实际上,使用foreach进行遍历时,无非就是调用People对象的GetEnumerator()方法,获取到了PeopleEnum对象。而后再调用PeopleEnum对象的MoveNext()、Reset()两个方法和Current属性实现遍历。即使我们的People和PeopleEnum不从IEnumerable和IEnumerator继承,只要实现了上述几种方法和属性,People对象同样也会被成功遍历。
三、其他继承了IEnumerable的C#内置类型
C#中许多有集合意义的数据类型都继承了IEnumerable接口,比如Dictionary和List。通常情况下凡是采用foreach能够遍历的类型都是继承了IEnumerable接口,比如List<int>继承自IEnumerable<int>,Dictionary<int,string>继承自IEnumerable<int,string>。下面的代码就是利用Dictionary和List对象的GetEnumerator()方法,返回了一个Enumerator对象,再利用该对象进行遍历:
Dictionary<int,string> dic = newDictionary<int,string>();
dic.Add(1, "Tom");
dic.Add(2, "Jerry");
dic.Add(3, "Hyman");
Dictionary<int,string>.Enumeratorenumerator = dic.GetEnumerator();
for (int i = 0; i< dic.Count;i++ )
{
enumerator.MoveNext();
Console.WriteLine(enumerator.Current.Value);
}
List<string>list = new List<string> { "123","456", "789"};
List<string>.Enumerator enumerator2 = list.GetEnumerator();
for (int j = 0; j< list.Count; j++)
{
enumerator2.MoveNext();
Console.WriteLine(enumerator2.Current);
}
最终结果如下:
Github位置:
https://github.com/HymanLiuTS/CSGroup
克隆本项目:
Git clone git@github.com:HymanLiuTS/ CSGroup.git
获取本文源代码:
git checkout CSL03