对于.NET Framework提供的“标准”的集合类型可以直接使用foreach,如(Array、ArrayList、HashTable),除此之外,对于自定义的集合对象,也可以使其支持foreach的使用,只要实现IEnumerable接口即可(刚提到的几种集合类型都实现了这个接口)。
先看个例子:
public class HelloCollection : IEnumerable
{
public IEnumerator GetEnumerator ()
{
yield return "Hello";
yield return "World";
}
}
class CustomerForeach
{
static void Main()
{
HelloCollection helloCollection = new HelloCollection();
foreach (string s in helloCollection)
{
Console.WriteLine(s + "……");
}
Console.ReadKey();
}
}
运行可以看到正确的输出了“Hello…… World……”,问题的关键就在 “IEnumerator”的 “IEnumerable.GetEnumerator()”这个方法,以及yield关键字,单步运行程序会发现程序运行至foreach语句之后跳转至HelloCollection中的GetEnumerator方法,然后遇到“yield return”就返回,接着执行下一个,直到返回所有的yield……
修改上述代码,比方说改为如下代码,先猜测下结果,然后运行看输出什么。
public class HelloCollection : IEnumerable
{
public IEnumerator GetEnumerator()
{
Console.WriteLine("跳转至GetEnumerator方法");
Console.WriteLine("即将输出");
yield return "Hello";
Console.WriteLine("下一个输出");
yield return "World";
}
}
class CustomerForeach
{
static void Main()
{
HelloCollection helloCollection = new HelloCollection();
foreach (string s in helloCollection)
{
Console.WriteLine("foreach方法");
Console.WriteLine(s );
}
Console.ReadKey();
}
}
结果输出的是
看明白了?遇到一个yield return 就返回到foreach,而且在foreach内部使用的s就是返回的值……
再看个代码 :
class CustomerForeach
{
static void Main()
{
Peoples ps = new Peoples();
foreach (People p in ps)
{
Console.WriteLine(p);
}
Console.ReadKey();
}
}
class People
{
public string Name;
public int Age;
//重写基类object的Tostring方法()以按一下格式提供有意义的信息
//姓名:年龄
public override string ToString()
{
//return base.ToString();
return Name + ":" + Age.ToString();
}
}
class Peoples:IEnumerable
{
private People[] objects;
private Random ran = new Random();
private void FillElements()
{
objects = new People[10];
for (int i = 0; i < 10; i++)
{
objects[i] = new People();
objects[i].Name = "People" + (i+1).ToString();
objects[i].Age = ran.Next(1,100);
}
}
public Peoples()
{
FillElements();
}
#region IEnumerable 成员
IEnumerator IEnumerable.GetEnumerator()
{
// throw new NotImplementedException();
foreach (People people in objects)
{
yield return people;
}
}
#endregion
}
这个自己测试吧,通过查找可以知道IEnumerable里就一个方法是IEnumerator GetEnumerator();而IEnumerator接口原型如下(查询VS2008文档得知)
以下是自带的解释
最后在加个例子,跟上述相关的
class CustomerForeach
{
static void Main()
{
int[] values = new int[10]{0,1,2,3,4,5,6,7,8,9};
ArrayList arrl = new ArrayList();
arrl.Add("Arr1");
arrl.Add("Arr3");
arrl.Add("Arr5");
Hashtable hst = new Hashtable();
hst.Add(2, "hst2");
hst.Add(4, "hst4");
hst.Add(6, "hst6");
PrintCollection(values);
PrintCollection(arrl);
PrintCollection(hst);
Console.ReadKey();
}
static void PrintCollection(IEnumerable obj)
{
//获取迭代访问器
IEnumerator itor = obj.GetEnumerator();
//只要集合中还有为访问的元素。movenext方法返回True
while (itor.MoveNext())
{
//itor.Current返回当前的对象
//本例仅简单的输出其Tostring()方法的结果
Console.WriteLine(itor.Current.ToString());
}
}
}
看明白了吗?