程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 先說IEnumerable,我們每天用的foreach你真的懂它嗎?,ienumerableforeach

先說IEnumerable,我們每天用的foreach你真的懂它嗎?,ienumerableforeach

編輯:C#入門知識

先說IEnumerable,我們每天用的foreach你真的懂它嗎?,ienumerableforeach


我們先思考幾個問題:

接下來,先開始我們的正文。

自己實現迭代器

.net中迭代器是通過IEnumerable和IEnumerator接口來實現的,今天我們也來依葫蘆畫瓢。

首先來看看這兩個接口的定義:

並沒有想象的那麼復雜。其中IEnumerable只有一個返回IEnumerator的GetEnumerator方法。而IEnumerator中有兩個方法加一個屬性。

接下來開發畫瓢,我們繼承IEnumerable接口並實現:

下面使用原始的方式調用:

有朋友開始說了,我們平時都是通過foreache來取值的,沒有這樣使用過啊。好吧,我們來使用foreach循環:

為什麼說基本上是等效的呢?我們先看打印結果,在看反編譯代碼。

由此可見,兩者有這麼個關系:

我們可以回答第一個問題了“為什麼在foreach中不能修改item的值?”:

我們還記得IEnumerator的定義嗎

 

接口的定義就只有get沒有set。所以我們在foreach中不能修改item的值。

我們再來回答第二個問題:“要實現foreach需要滿足什麼條件?”:

必須實現IEnumerable接口?NO

我們自己寫的MyIEnumerable刪掉後面的IEnumerable接口一樣可以foreach(不信?自己去測試)。

所以要可以foreach只需要對象定義了GetEnumerator無參方法,並且返回值是IEnumerator或其對應的泛型。細看下圖:

也就是說,只要可以滿足這三步調用即可。不一定要繼承於IEnumerable。有意思吧!下次面試官問你的時候一定要爭個死去活來啊,哈哈!

yield的使用

你肯定發現了我們自己去實現IEnumerator接口還是有些許麻煩,並且上面的代碼肯定是不夠健壯。對的,.net給我們提供了更好的方式。

你會發現我們連MyIEnumerator都沒要了,也可以正常運行。太神奇了。yield到底為我們做了什麼呢?

好家伙,我們之前寫的那一大坨。你一個yield關鍵字就搞定了。最妙的是這塊代碼:

這就是所謂的狀態機吧!

我們繼續來看GetEnumerator的定義和調用:

我們調用GetEnumerator的時候,看似裡面for循環了一次,其實這個時候沒有做任何操作。只有調用MoveNext的時候才會對應調用for循環:

為什麼Linq to Object中要返回IEnumerable?”:

因為IEnumerable是延遲加載的,每次訪問的時候才取值。也就是我們在Lambda裡面寫的where、select並沒有循環遍歷(只是在組裝條件),只有在ToList或foreache的時候才真正去集合取值了。這樣大大提高了性能。

如:

這個時候得到了就是IEnumerable對象,但是沒有去任何遍歷的操作。(對照上面的gif動圖看)

什麼,你還是不信?那我們再來做個實驗,自己實現MyWhere:

返回的就是IEnumerable),只有執行到ToList的時候才代碼才真正的去遍歷篩選。

這裡的MyWhere其實可以用擴展方法來實現,提升逼格。(Linq的那些查詢操作符就是以擴展的形式實現的)[了解擴展方法]。

怎樣高性能的隨機取IEnumerable中的值

這段代碼來源《深入理解C#》,個人覺得非常妙。貼出來給大家欣賞哈。

 

個人對迭代器的理解和總結,不一定對。輕拍!

文章首鏈:http://www.cnblogs.com/zhaopei/p/5769782.html

demo下載:http://pan.baidu.com/s/1dE94c1b

感謝您的閱讀。如果文章對您有用,那麼請輕輕點個贊,以資鼓勵。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved