C# 使用foreach遍历类中的对象

foreach可以对字符串数组,list集合等进行遍历,但是它如何对普通类进行遍历呢,使得我们可以对类中的对象属性进行操作呢。在这里我简单总结了三种方法,使得foreach可以对普通类进行遍历。

关于IEnumerable与IEnumerator
IEnumerable是一个非常简单的接口,它仅仅包含了一个返回IEnumerator接口对象的抽象方法:GetEnumerator()。而IEnumerator接口提供了一个属性和两个抽象方法分别是:
object Current { get; }
bool MoveNext();
void Reset();
Current表示遍历的集合的当前元素,MoveNext()实现移动Enumerator(枚举器)到下一个位置,Reset()顾名思义,即重置枚举器。
那么,这就说明实现该接口的集合都可以进行foreach遍历。所以我们会发现list集合有继承IEnumerable接口并实现了GetEnumerator()方法,从而实现了枚举器的功能。类似的Array等集合类都有实现该接口。那么我们所写的普通类只要实现了该接口,就可以进行foreach遍历。

一. 使用yield return
1. 实现
定义一个person类,如下:

    class Person
    {
        public string name;
        public int age;
        public string sex;
        public Person(string name, int age, string sex)
        {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
    }

然后定义一个PeopleInfo类,这个类中记录了多个Person对象,放在一个对象数组中。如果想遍历这个类获取这些对象信息,那就需要实现IEnumerable接口中的GetEnumerator()方法,如下:

    class PeopleInfo:IEnumerable
    {
        public Person[] person;
        public PeopleInfo(Person[] persons)
        {
            this.person = new Person[persons.Length];
            for (int i = 0; i < persons.Length; i++)
            {
                this.person[i] = persons[i];
            }
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            for (int i = 0; i < person.Length; i++)
            {
                yield return person[i];
            }
        }
    }

在GetEnumerator使用了yield return,它会在GetEnumerator中for每循环一次就会返回一个对象。编译器会生成一个状态机来维护迭代器的状态,所以yield return可以准确的知道要返回哪一个对象。
2. 测试

            Person[] person ={
                                new Person("deas",15,"male"),
                                new Person("dad",18,"male"),
                                new Person("aliex",25,"female")
                            };
            PeopleInfo personInfo = new PeopleInfo(person);
            foreach (Person item in personInfo)
            {
                Console.WriteLine(item.name+"  "+item.age+"  "+item.sex);
            }
            Console.ReadKey();

  1. 结果
    这里写图片描述

    二. 借用Array类
    改变上边的GetEnumerator方法为:
        IEnumerator IEnumerable.GetEnumerator()
        {
            //表示返回array的GetEnumerator
            return this.person.GetEnumerator();
        }

可以知道Person是一个Array类的实例,所以直接返回该实例的GetEnumerator方法即可,在Array集合类中就有GetEnumerator的具体实现方法。这里测试与结果与上边的一样,不再做阐述。

三. 自己实现IEnumerator接口
前面说过foreach能够遍历集合是因为集合实现了IEnumerator接口方法那么我们自己也可以实现该接口,如下:

    class PersonIEnumerator:IEnumerator
    {
        private int position = -1;
        private PeopleInfo personInfo;
        public PersonIEnumerator(PeopleInfo info)
        {
            this.personInfo = info;
        }

        public object Current
        {
            get 
            {
                return personInfo.person[position];
                throw new NotImplementedException(); 
            }
        }

        public bool MoveNext()
        {
            position++;
            return position < personInfo.person.Length;
            throw new NotImplementedException();
        }

        public void Reset()
        {
            position = -1;
            throw new NotImplementedException();
        }
    }

这里定义了一个专门遍历PeopleInfo 类的迭代器,在PersonIEnumerator类中实现了 IEnumerator 接口,然后实现GetEnumerator方法来返回IEnumerator对象如下:

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator)new PersonIEnumerator(this);
        }

然后进行测试可以得到相同的结果。

总结
可以发现第三种方法是比较麻烦的,但是它对IEnumerator 和IEnumerable的理解很有帮助,当然在实际看法中用前两种应该是很方便的。当然我们也可以让一个普通类继承某种类型的集合(list,Dictionary)或者实现(Ilist,IDictionary)的接口来完成对这个普通类的foreach遍历。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值