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

来源:http://www.cnblogs.com/zhaopei/archive/2016/08/15/5769782.html
-Advertisement-
Play Games

我們先思考幾個問題: 接下來,先開始我們的正文。 自己實現迭代器 .net中迭代器是通過IEnumerable和IEnumerator介面來實現的,今天我們也來依葫蘆畫瓢。 首先來看看這兩個介面的定義: 並沒有想象的那麼複雜。其中IEnumerable只有一個返回IEnumerator的GetEnu ...


我們先思考幾個問題:

  1. 為什麼在foreach中不能修改item的值?
  2. 要實現foreach需要滿足什麼條件?
  3. 為什麼Linq to Object中要返回IEnumerable?

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

自己實現迭代器

.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:

現在看到了吧。執行到MyWhere的時候什麼動作都沒有(返回的就是IEnumerable),只有執行到ToList的時候才代碼才真正的去遍歷篩選。

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

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

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

 

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

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

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

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

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 源代碼如下: typedef struct _IMAGE_FILE_HEADER { +04h WORD Machine; // 運行平臺 +06h WORD NumberOfSections; // 文件的區塊數目 +08h DWORD TimeDateStamp; // 文件創... ...
  • 問題 一般Android手機用usb數據線連接到windows操作系統的電腦上後,會自動將手機存儲卡以移動存儲的方式顯示在電腦里. 但是如果操作系統是Mac的,就沒有這個存儲設備.問題來了,Mac電腦如何讀取手機上的文件呢? 解決方式 從Android的網站下載一個傳輸工具,地址是, 安裝打開後,會 ...
  • 比如 ssh 10.0.1.23,出現以下情況: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @@@@@@@@@@@@@@@ ...
  • 版權聲明:本文為MULTIBEANS ORG研發跟隨文章,未經MLT ORG允許不得轉載。 最近做項目,需要開發安卓應用,實現串口的收發,目測CH340G在安卓手機上非常麻煩,而且驅動都是Java版本的, 就沒選擇,博主在大二的時候學習過Java SE基本的語法,寫過一些小程式就放棄了Java的道路 ...
  • 最近在做項目中用到2013中的ReportView11 在本機IIS中使用完全沒問題 但是放到伺服器上總是出問題 解決辦法:(1)首先在自己機器上開發的時候 是不用引用 Microsoft.ReportViewer.Common.dll和Microsoft.ReportViewer.WebForms ...
  • C# 軟體配置方法。通常情況下我們使用appSetting來進行配置,通過 Glacier 可以使用嵌入的 HOCON 或獨立的 HOCON 配置文件配置,同時支持類型綁定功能,方便統一管理軟體配置。 ...
  • 最近閑來無事給自己寫了家庭財務收支管理系統,也就包含支出管理,收入管理和一些統計功能。 先說登錄模塊,因為涉及GET和POST請求,這些東西都是能被監控和抓取的所以就考慮這使用RSA加密解密方式傳輸用戶名和密碼參數,頁面JS如下: 1 /*需要引入三個JS文件,BigInt.js、RSA.js和Ba ...
  • 靜態 1、普通成員普通成員都是屬於對象的用對象調用 2、靜態成員靜態成員是屬於類的用類名調用 class FenBi{public int length;//普通成員public string color;//} static 靜態關鍵字 靜態方法裡面不能包含普通成員 普通方法裡面可以包含靜態成員 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...