[C#.NET] 建立具有foreach的類別,實作 IEnumerator / IEnumerable

  • 27682
  • 0
  • 2013-07-05

[C#.NET] 建立具有foreach的類別,實作 IEnumerator / IEnumerable

先來看一下這兩這介面的成員,這些成員都是必須要實作的。

public interface IEnumerable
{
    IEnumerator GetEnumerator();//傳回會逐一查看集合的列舉程式。
}
public interface IEnumerator
{
    // 方法
    bool MoveNext();//將列舉值往前推至下集合中的下一個項目。如果成功則返回為 true;如果超過集合結尾,則返回false。
    void Reset();//設定列舉值至它的初始位置,這是在集合中第一個元素之前。
    // 屬性
    object Current { get; }//取得集合中目前的項目。
}

 

 

實作 IEnumerable 介面便可以讓類別可以使用foreach語法。

IEnumerator 介面是讓類別支援反覆運算(Iteration)。

 

接下來用程式碼來實現

首先我先需要一個MemberInform類別裡面有一些屬性

class MemberInfomation
{
    public string Name { get; set; }
    public int ID { get; set; }
    public int Age { get; set; }
}

 

然後在EnumDemo類別裡繼承IEnumerable與IEnumerator介面,並實作這些方法以及屬性。

 

class EnumerDemo : IEnumerable, IEnumerator
{
    //定義索引
    private int index = -1;
    private MemberInfomation[] member = new MemberInfomation[3];
    public EnumerDemo()
    {
        member[0] = new MemberInfomation { Name = "Orochi", Age = 24, ID = 1175 };
        member[1] = new MemberInfomation { Name = "Blinda", Age = 23, ID = 1265 };
        member[2] = new MemberInfomation { Name = "Ninicat", Age = 25, ID = 1295 };
    }

    #region IEnumerable
    //傳回會逐一查看集合的列舉程式。
    public IEnumerator GetEnumerator()
    {
        return (IEnumerator)this;
    }
    #endregion

    #region IEnumerator
    //設定列舉值至它的初始位置,這是在集合中第一個元素之前。
    public void Reset()
    {
        index = -1;
    }

    //取得集合中目前的項目。
    public object Current
    {
        get { return member[index]; }
    }

    //將列舉值往前推至下集合中的下一個項目
    public bool MoveNext()
    {
        index++;
        return index >= member.Length ? false : true;
    }
    #endregion
}

 

 

接著在主程式裡呼叫,很簡單的就讓類別可以用foreach列舉

static void Main(string[] args)
{
    EnumerDemo member = new EnumerDemo();
    foreach (MemberInfomation item in member)
    {
        Console.WriteLine("ID:{0}, Name:{1}, Age:{2}", item.ID, item.Name, item.Age);
    }
    Console.Read();
}

 

image

要實現具有foreach的功能還挺麻煩的,除了要定義一個類別之外,還要實作IEnumerator / IEnumerable 這兩個界面,還挺麻煩的,但.NET裡的yield節省了這些麻煩,將Enum類別改成下面的樣子。

class EnumerDemo
{
    //定義索引
    private int index = 0;
    private MemberInfomation[] member = new MemberInfomation[3];
    public EnumerDemo()
    {
        member[0] = new MemberInfomation { Name = "Orochi", Age = 24, ID = 1175 };
        member[1] = new MemberInfomation { Name = "Blinda", Age = 23, ID = 1265 };
        member[2] = new MemberInfomation { Name = "Ninicat", Age = 25, ID = 1295 };
    }

    public IEnumerable<MemberInfomation> GetMembers()
    {
        for (int i = 0; i < member.Length; i++)
        {
            yield return member[i];
        }
    }
}

 

 

在主程式裡就在GetMembers方法使用foreach,有了yield就可以省掉自定類別實作介面的程式碼。

static void Main(string[] args)
{
    EnumerDemo member = new EnumerDemo();

    foreach (MemberInfomation item in member.GetMembers())
    {
        Console.WriteLine("ID:{0}, Name:{1}, Age:{2}", item.ID, item.Name, item.Age);
    }
    Console.Read();
}

 

 

看到這裡可能有人會問:『幹嘛要用foreach來列舉資料,我覺得for迴圈也很好用阿,為何要多此一舉呢?』。是的,沒錯,用for迴圈的確就能處理掉這些工作,在設計模式(Design Patterns)裡有一個模式叫Iterator,它主要是希望把物件巡訪的順序 (iteration) 跟依序拿到物件後要作什麼事 (process) 分開 - 安德魯

列舉物件歸列舉,演算法歸演算法,我們不需要演算法怎麼處理,我們只要按它擺放的物件順序拿資料就好了,更是能將程式碼的藕合度降低。

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo