自定义类型使用foreach循环

来源:互联网 发布:微信打印软件 编辑:程序博客网 时间:2024/05/22 05:05

示例代码:

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 Peopleforeach(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 Systempublic 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<T> : 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<T>(this.persons);    }}

更改PersonEnum:

using System;using System.Collections;public class PersonEnum<T> : 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

0 0
原创粉丝点击