posted at 2017.5.17 20:51 by 风信子
我们先看IEnumerable和IEnumerator两个接口的语法定义。其实IEnumerable接口是非常的简单,只包含一个抽象的方法GetEnumerator(),它返回一个可用于循环访问集合的IEnumerator对象。IEnumerator对象有什么呢?它是一个真正的集合访问器,没有它,就不能使用foreach语句遍历集合或数组,因为只有IEnumerator对象才能访问集合中的项,假如连集合中的项都访问不了,那么进行集合的循环遍历是不可能的事情了。
那么让我们看看IEnumerator接口有定义了什么东西。看下图我们知道IEnumerator接口定义了一个Current属性,MoveNext和Reset两个方法,这是多么的简约。既然IEnumerator对象时一个访问器,那至少应该有一个Current属性,来获取当前集合中的项吧。MoveNext方法只是将游标的内部位置向前移动(就是移到一下个元素而已),要想进行循环遍历,不向前移动一下怎么行呢?
详细讲解:
说到IEnumerable总是会和IEnumerator、foreach联系在一起。
C# 支持关键字foreach,允许我们遍历任何数组类型的内容:
//遍历数组的项
int[] myArrayOfInts = {10,20,30,40};
foreach(int i in my myArrayOfInts)
{
Console.WirteLine(i);
}
虽然看上去只有数组才可以使用这个结构,其实任何支持GetEnumerator()方法的类型都可以通过foreach结构进行运算。
所以,要想类也可以使用foreach遍历其中的项,那我们就要修改类型使之支持这些接口。可以手工实现每一个方法,不过这得花费不少功夫。虽然自己开发GetEnumerator()、MoveNext()、Current和Reset()也没有问题,但有一个更简单的办法。因为System.Array类型和其他许多类型(如List)已经实现了IEnumerable和IEnumerator接口,你可以简单委托请求到System.Array。如下所示:
- namespace MyCarIEnumerator
- {
- public class Garage:IEnumerable
- {
- Car[] carArray = new Car[4];
-
-
- public Garage()
- {
- carArray[0] = new Car("Rusty", 30);
- carArray[1] = new Car("Clunker", 50);
- carArray[2] = new Car("Zippy", 30);
- carArray[3] = new Car("Fred", 45);
- }
- public IEnumerator GetEnumerator()
- {
- return this.carArray.GetEnumerator();
- }
- }
- }
-
-
- namespace MyCarIEnumerator
- {
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("*********Fun with IEnumberable/IEnumerator************\n");
- Garage carLot = new Garage();
-
-
- foreach (Car c in carLot)
- {
- Console.WriteLine("{0} is going {1} MPH", c.CarName, c.CurrentSpeed);
- }
-
- Console.WriteLine("GetEnumerator被定义为公开的,对象用户可以与IEnumerator类型交互,下面的结果与上面是一致的");
-
- IEnumerator i = carLot.GetEnumerator();
- while (i.MoveNext())
- {
- Car myCar = (Car)i.Current;
- Console.WriteLine("{0} is going {1} MPH", myCar.CarName, myCar.CurrentSpeed);
- }
- Console.ReadLine();
- }
- }
- }
IEnumerable<T>接口
实现了IEnmerable<T>接口的集合,是强类型的。它为子对象的迭代提供类型更加安全的方式。
- public class ListBoxTest:IEnumerable<String>
- {
- private string[] strings;
- private int ctr = 0;
-
- #region IEnumerable<string> 成员
-
- public IEnumerator<string> GetEnumerator()
- {
- foreach (string s in strings)
- {
- yield return s;
- }
- }
-
- #endregion
-
- #region IEnumerable 成员
-
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- #endregion
-
-
- public ListBoxTest(params string[] initialStrings)
- {
-
- strings = new String[8];
-
- foreach (string s in initialStrings)
- {
- strings[ctr++] = s;
- }
- }
-
-
- public void Add(string theString)
- {
- strings[ctr] = theString;
- ctr++;
- }
-
-
- public string this[int index]
- {
- get {
- if (index < 0 || index >= strings.Length)
- {
-
- }
- return strings[index];
- }
- set {
- strings[index] = value;
- }
- }
-
-
- public int GetNumEntries()
- {
- return ctr;
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
-
- ListBoxTest lbt = new ListBoxTest("Hello", "World");
-
-
- lbt.Add("Who");
- lbt.Add("Is");
- lbt.Add("Douglas");
- lbt.Add("Adams");
-
-
- string subst = "Universe";
- lbt[1] = subst;
-
-
- foreach (string s in lbt)
- {
- Console.WriteLine("Value:{0}", s);
- }
- Console.ReadKey();
- }
- }
综上所述,一个类型是否支持foreach遍历,必须满足下面条件:
方案1:让这个类实现IEnumerable接口
方案2:这个类有一个public的GetEnumerator的实例方法,并且返回类型中有public 的bool MoveNext()实例方法和public的Current实例属性。
eb478996-9dcb-44aa-bc36-40575f0e0cc3|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04
Tags: 接口, 类, c#
IT技术