示例代码:
List<string> names = new List<string>();
foreach(string name in names)
{
Console.WriteLine(name);
}
以上foreach语句代码中,names类型是List。c sharp允许用户自定义自己的类型以便使用foreach语句。假设有类型People定义如下,
using System;
public class People
{
private Person[] persons;
public People(Person[] persons)
{
this.persons = new Person[persons.Length];
for(int i = 0; i < persons.Length; i++)
{
this.persons[i] = persons[i];
}
}
}
其中,Person类的定义如下:
using System;
public class Person
{
private string name;
private int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public override string ToString()
{
return this.name + " " + this.age;
}
}
我们期待的使用foreach的效果如下:
// persons' type is People
foreach(Person person in persons)
{
Console.WriteLine(person);
}
foreach语句的原理是从实现IEnumerable接口的类中调用GetEnumerator()方法,获得一个实现了IEnumerator的类,这个类中有Current, MoveNext等foreach语句必要的调用方法。这里,我们把实现了IEnumerable和IEnumerator的类看作使用foreach语句的工具类,即People和PersonEnum看作工具,实际数据Person看作被操作类型,如下:
更改People类实现IEnumerable接口。
public class People : IEnumerable
{
private Person[] persons;
public People(Person[] persons)
{
this.persons = new Person[persons.Length];
for(int i = 0; i < persons.Length; i++)
{
this.persons[i] = persons[i];
}
}
// implement the interface method explicitly
IEnumerator IEnumerable.GetEnumerator()
{
return new PersonEnum(this.persons);
}
}
PersonEnum是实现了IEnumerator接口的由IEnumerable返回的类。实现PersonEnum类如下:
public class PersonEnum : IEnumerator
{
private Person[] persons;
private int position = -1;
public PersonEnum(Person[] persons)
{
this.persons = persons;
}
public bool MoveNext()
{
position++;
return position < this.persons.Length;
}
// return type is object
object IEnumerator.Current
{
get { return Current; }
}
public void Reset()
{
position = -1;
}
public Person Current
{
get
{
try
{
return this.persons[position];
}
catch(IndexOutOfRangeException)
{
return null;
}
}
}
}
查看使用效果:
using System
public sealed class Program
{
static void Main(string[] args)
{
Person[] persons = new Person[3];
persons[0] = new Person("Owen", 22);
persons[1] = new Person("Vincent", 21);
persons[2] = new Person("Ricy", 20);
People people = new People(persons);
foreach (Person person in people)
Console.WriteLine(person);
}
}
使用IEnumerable和IEnumerator,由于没有确定被操作的类型,使得操作对象为object,如Current属性的返回值,
object IEnumerator.Current
这使得类型不安全,为了确定类型,建议使用泛型化的IEnumerable和IEnumerator。
注意,实现接口IEnumerable和IEnumerator与实现接口IEnumerable和IEnumerator的类MyEnumberable是否需要泛型化,可以作出如下讨论。
public class MyEnumerable : IEnumerable
这种情况,使得MyEnumerable类正如上述实例中的People类,操作的只能是一种确定的类型(Person)。如果需要扩展被操作的类型,工具类People和PersonEnum操作其他类型,可以做如下泛型化:
public class People : IEnumerable
public class PersonEnum : IEnumerator
代码如下:
using System;
using System.Collections;
public class People : IEnumerable
{
// type to be operate could be any type
private T[] persons;
public People(T[] persons)
{
this.persons = new T[persons.Length];
for (int i = 0; i < persons.Length; i++)
{
this.persons[i] = persons[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return new PersonEnum(this.persons);
}
}
更改PersonEnum:
using System;
using System.Collections;
public class PersonEnum : IEnumerator
{
private T[] persons;
private int position = -1;
public PersonEnum(T[] persons)
{
this.persons = persons;
}
public bool MoveNext()
{
position++;
return position < this.persons.Length;
}
object IEnumerator.Current
{
get { return Current; }
}
public void Reset()
{
position = -1;
}
public T Current
{
get
{
try
{
return this.persons[position];
}
catch (IndexOutOfRangeException)
{
return default(T);
}
}
}
}
注意泛型化之后,Current的catch块中返回default(T),值类型返回0,引用类型返回null。
检查效果:
using System;
public sealed class Program
{
static void Main(string[] args)
{
Person[] persons = new Person[3];
persons[0] = new Person("Owen", 22);
persons[1] = new Person("Vincent", 21);
persons[2] = new Person("Ricy", 20);
People people = new People(persons);
foreach (Person person in people)
Console.WriteLine(person);
string[] namelist = new string[3];
namelist[0] = "Owen";
namelist[1] = "Vincent";
namelist[2] = "Ricy";
People<string> names = new People<string>(namelist);
foreach (string name in names)
Console.WriteLine(name);
}
}
若MyEnumerable类实现IEnumerable,其自身不做泛型化,
public People : IEnumerable
这样的类型定义直接导致报错,
the type or namespace name ‘T’ could not be found
所以,People必须泛型化。
public People : IEnumerable