1. 程式人生 > >C# 使用foreach遍歷類中的物件

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遍歷。