[原譯]實現IEnumerable接口&理解yield關鍵字


著作權聲明:本文由http://leaver.me 翻譯,歡迎轉載分享。請尊重作者勞動,轉載時保留該聲明和作者博客鏈接,謝謝!

本文討論題目的內容。然后討論IEnumerable接口如何使得foreach語句可以使用。之后會展示如果實現自定義的集合類,該集合類實現了IEnumerable接口。Yield關鍵字和遍歷集合后面也討論。

背景

一使用集合。就發現遍歷集合就跟着來了。遍歷集合最好的方式是實現迭代器模式-Understanding and Implementing the Iterator Pattern in C# and C++(這篇文章我過幾天翻譯一下) ,C#提供foreach來以一種優雅的方式遍歷

只要集合實現了IEnumerable 接口就可以用foreach來遍歷。

使用代碼

首先先看一下內置的集合類如何使用foreach來遍歷的。ArrayList實現了IEnumerable 接口。我們看一下

// 看一下實現了IEnumerable 接口的集合如何遍歷
ArrayList list = new ArrayList();

list.Add("1");
list.Add(2);
list.Add("3");
list.Add('4');

foreach (object s in list)
{
    Console.WriteLine(s);
}

 

 

遍歷泛型集合類

Arraylist 是一個通用集合類,遍歷泛型集合類也可以。因為這些泛型集合類實現了IEnumerable<T>接口,看一下吧。

// 遍歷實現了IEnumerable<T>接口的泛型類
List<string> listOfStrings = new List<string>();

listOfStrings.Add("one");
listOfStrings.Add("two");
listOfStrings.Add("three");
listOfStrings.Add("four");

foreach (string s in listOfStrings)
{
    Console.WriteLine(s);
} 

發現了吧。我們自定義的集合類或是泛型集合類應該實現IEnumerable和IEnumerable<T>接口。這樣就可以遍歷了。

 

理解yield關鍵字

在寫個實現接口的例子之前,先理解一下yield關鍵字,yield會記錄集合位置。當從一個函數返回一個值的時候,yield可以用。

如下的普通的方法。不論調用多少次,都只會返回一個return

static int SimpleReturn()
{
    return 1;
    return 2;
    return 3;
}

static void Main(string[] args)
{
    // 看看
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
}

 

 

原因就是普通的return語句不保留函數的返回狀態。每一次都是新的調用。然后返回第一個值。

但是使用下面的語句替換后就不一樣。當函數第二次調用的時候。會從上次返回的地方繼續調用

static IEnumerable<int> YieldReturn()
{
    yield return 1;
    yield return 2;
    yield return 3;
}
static void Main(string[] args)

{
    // 看看yield return的效果
    foreach (int i in YieldReturn())
    {
        Console.WriteLine(i);
    }
}

 

顯然返回1,2,3,唯一要注意的就是函數需要返回IEnumerable。,然后通過foreach調用。

在自定義的集合類里實現Ienumerable接口

現在如果我們在我們的自定義集合里定義一個方法。來迭代所有元素。然后通過使用yield返回。我們就可以成功了。

好。我們定義MyArrayList 類,實現IEnumerable 接口,該接口就會強制我們實現GetEnumerator 函數。這里我們就要使用yield了。

class MyArrayList : IEnumerable
{
    object[] m_Items = null;
    int freeIndex = 0;

    public MyArrayList()
    {
        // 對了方便我直接用數組了,其實應該用鏈表
       m_Items = new object[100];
    }

    public void Add(object item)
    {
        // 考慮添加元素的時候
        m_Items[freeIndex] = item;
        freeIndex++;
    }

    // IEnumerable 函數
    public IEnumerator GetEnumerator()
   {
       foreach (object o in m_Items)
        {
           // 檢查是否到了末尾。數組的話。。。沒寫好
            if(o == null)
            {
                break;
            }

            // 返回當前元素。然后前進一步
            yield return o;
        }
    }
}

 

 

 

之后你就可以用foreach遍歷了。

static void Main(string[] args)
{
    //看看調用部分
    MyArrayList myList = new MyArrayList();

    myList.Add("1");
    myList.Add(2);
    myList.Add("3");
    myList.Add('4');

    foreach (object s in myList)
    {
        Console.WriteLine(s);
    }
}

 

 

這個類啊。沒寫好。也不完整。只要是讓你理解。。模擬一下而已。

自定義泛型類里實現Ienumerable<T>接口

class MyList<T> : IEnumerable<T>
{
    T[] m_Items = null;
    int freeIndex = 0;

    public MyList()
    {
        // 為了方便。使用數組
        m_Items = new T[100];
    }

    public void Add(T item)
    {
        //添加元素
        m_Items[freeIndex] = item;
        freeIndex++;
    }

    #region IEnumerable<T> Members 

    public IEnumerator<T> GetEnumerator()
    {
        foreach (T t in m_Items)
        {
            //檢查是否到了末尾。數組的話。。。沒寫好
            if (t == null) // 如果T不是一個可空類型。就中斷
            {
                break;
            }

            // 返回當前元素,然后前進一步
            yield return t;
        }
    }

    #endregion

     #region IEnumerable Members
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        // 此處調用泛型版本
        return this.GetEnumerator();
    }

    #endregion
}

 

 

之后就可以使用foreach了。

static void Main(string[] args)
{
    // 使用示例
    MyList<string> myListOfStrings = new MyList<string>();

    myListOfStrings.Add("one");
    myListOfStrings.Add("two");
    myListOfStrings.Add("three");
    myListOfStrings.Add("four");

    foreach (string s in myListOfStrings)
    {
        Console.WriteLine(s);
    }
}

 

 源代碼下載

EnumerableDemo.7z

原文地址: A-Beginners-Tutorial-on-Implementing-IEnumerable-I

著作權聲明:本文由http://leaver.me 翻譯,歡迎轉載分享。請尊重作者勞動,轉載時保留該聲明和作者博客鏈接,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM