跳過到頁腳內容
Iron Academy Logo
學習 C#
學習 C#

其他分類

C# 中的屈 yield 介紹—它是什麼、如何使用以及何時有用

Tim Corey
43m 58s

當您第一次接觸C#中的yield關鍵字時,可能會感到困惑。 它究竟如何運作? 應該在何時使用yield return,而不是傳統的return語句? 為了獲得完整的理解,我們將通過Tim Corey的優秀YouTube教學"C#中的Yield介紹 - 它是什麼,如何使用,以及什麼時候有用"進行詳細解釋。

在本指南中,我們將參考Tim影片中的特定時間點,以便於瀏覽,並包含實際範例展示yield如何改變您處理資料流、大型集合和延遲評估的方式。

C#中Yield關鍵字介紹

Tim首先介紹了yield關鍵字,並強調它對於首次遇到它的開發者來說常常令人困惑。他解釋了yield語句允許方法暫停執行、保留其狀態,然後在下一次調用時從中斷處繼續。 Tim強調理解yield對於高效處理資料至關重要,特別是在處理大型資料集或實現自定義迭代邏輯時。

建立簡單範例:類別Program和靜態Void Main

為了消除干擾,Tim在Visual Studio中創建了一個名為"YieldDemoApp"的簡單控制台應用程式。

Understanding Yield In Csharp 1 related to 建立簡單範例:類別Program和靜態Void Main

Yield在C#中實際做了什麼

然後Tim深入理論。 在2:04,他描述了yield的行為:不再一次處理整個集合,yield語句保留了一個位置——就像把大拇指放進書中——以便執行可以暫停稍後恢復。

這種行為對於延遲執行至關重要,其中只有在需要時才會生成值,而不是預先計算所有內容。 Tim的描述清楚地奠定了理解yield return如何運作的基礎。

撰寫範例程式碼

在類別Program的靜態void Main方法中,他設置了基本的首尾訊息,例如"應用程式開始"和"應用程式結束",使用Console.WriteLine,有助於清晰地可視化稍後使用foreach循環的流程。

這個初始的程式碼範例專注於yield實現,而不涉及任何UI複雜性。

創建PersonModel類

為了示範,Tim創建了一個具有FirstName和LastName屬性以及構造函數的PersonModel類。 當創建PersonModel物件時,會打印一條訊息,指出初始化的用戶。 這有助於可視化對象是在何時創建,何時被消耗。

Understanding Yield In Csharp 2 related to 創建PersonModel類

這個簡單的生成程式碼步驟為使用自定義迭代器做好了準備。

構建具有傳統列表返回的DataAccess類

在5:06,Tim轉至具有返回IEnumerable的方法GetPeople的DataAccess類。 最初,返回值為一個由三個PersonModel實例(Tim Corey、Sue Storm和Jane Smith)填充的列表。

Understanding Yield In Csharp 3 related to 構建具有傳統列表返回的DataAccess類

該迭代器方法在迭代開始之前立即將所有對象加載到內存中,這是一個重要點,Tim稍後將其與使用yield進行對比。

Understanding Yield In Csharp 4 related to 構建具有傳統列表返回的DataAccess類

演示列表的內存使用

在運行foreach循環後,Tim展示了所有三個用戶都是在第一次讀取元素之前創建的。 這突出了一個處理大集合或大型資料集時的潛在問題——高內存使用。

Understanding Yield In Csharp 5 related to 演示列表的內存使用

Tim解釋說,如果我們有一千個用戶,甚至只需要少數,我們也會創建一千個對象,導致內存分配效率低下。

更改為Yield Return進行延遲執行

在10:01,Tim修改GetPeople使用yield return,而不是創建臨時集合(列表)。 每個yield return語句都直接一次發出一個PersonModel。

方法中的這段關鍵程式碼允許延遲評估,只有在foreach需要時才生成下一個元素。

Tim還澄清,方法的返回類型必須是IEnumerable,並且使用列表會打破延遲執行的目的。

除錯:編譯器如何生成Yield的程式碼

Tim使用斷點逐步檢查過程。 他表明在第一次MoveNext調用前,序列為空。 只有當foreach需要下一個值時,編譯器才會觸發迭代器塊並執行yield return num行,這會初始化並返回PersonModel。

Understanding Yield In Csharp 6 related to 除錯:編譯器如何生成Yield的程式碼

Tim強調,編譯器在底層生成特別的狀態機來管理已暫停和已恢復的執行。

使用Yield Return的好處和效率

Tim解釋為何yield如此高效:

  • 您可以一次檢索一條記錄。

  • 您可以限制所需的int計數。

  • 您可以避免將整個集合加載到記憶體中。

  • 您提高了可擴展性,尤其是在處理大型檔案或資料流時。

通過使用LINQ的.Take(2),Tim演示了即使存在三個yield return語句,只有兩個對象被初始化——強調了延遲執行的實際作用。

實際範例:使用Yield的質數生成器

Tim在Generators類中建立了一個新的靜態IEnumerable GetPrimeNumbers()方法。 在這個無限循環中,Tim使用輔助的IsPrimeNumber(int number)函數檢查質數性。 如果數字是質數,他將使用yield return number來發出它。

這個範例表明,yield在安全處理無限序列方面至關重要。

若沒有yield,程式碼將因無限制的記憶體消耗而崩潰。 然而,使用yield,延遲執行確保了數字是按需生成的。

使用Take()抓取質數

Tim然後展示如何安全地只抓取固定數量的質數:

var primeNumbers = Generators.GetPrimeNumbers().Take(10000);
var primeNumbers = Generators.GetPrimeNumbers().Take(10000);

這段程式碼寫在靜態void Main中,能有效抓取10,000個質數。

因為yield return逐一生成數字,所以記憶體使用量保持低。

自定義迭代:使用GetEnumerator和MoveNext

Tim更進一步解釋如何手動控制迭代。

他創建了var iterator = primeNumbers.GetEnumerator(),然後使用int i的for循環和調用iterator.MoveNext()手動抓取元素。

這種手動方法使自定義迭代成為可能——只有在需要時才請求下一個值,並顯示該方法精確地從上次暫停處恢復。

常見錯誤:在Yielded集合上使用ToList()

在36:45,Tim警告:將yield序列轉換為名單的.ToList()導致立即完全評估。

如果在無限序列上調用.ToList(),您有可能使您的應用程式崩潰。

Tim強調,yield return旨在進行延遲評估,調用.ToList()會打破這一模式,強迫完全記憶體實現。

在使用LINQ方法時,Tim建議謹慎考慮何時引入.ToList()。

總結:為何Yield是一個強大的工具

Tim以強調即使yield關鍵字會增加一點開銷(持有狀態機),但減少的記憶體使用和延遲評估的優勢,使其在處理以下情況時成為強大的工具:

  • 大型資料集

  • 大型檔案

  • 自定義迭代器

  • 無限序列

  • 資料流。

  • 延遲處理。

他建議在不同專案中練習yield,來加深對yield return的理解,並避免常見陷阱。

Tim最後邀請觀眾分享他們如何在實際代碼中使用yield。

結論

通過觀看Tim Corey的影片,我們看到yield關鍵字給C#帶來的巨大好處。 從創建自定義迭代器到高效管理大型集合,yield return允許函數返回更聰明且更具記憶體效能。 無論您是處理var number、var point、var reader、var connection,或者大型資料集,掌握yield可以顯著提升您的C#編碼技巧。

如果您還沒探索過使用yield,現在是透過簡單範例進行練習並更好地了解yield return在C#編譯器內部如何工作的最佳時機。 請務必查看Tim的官方YouTube頻道,以獲得更多有洞察力的影片。

Hero Worlddot related to C# 中的屈 yield 介紹—它是什麼、如何使用以及何時有用
Hero Affiliate related to C# 中的屈 yield 介紹—它是什麼、如何使用以及何時有用

通過分享您所愛的東西賺得更多

您是否在為使用.NET、C#、Java、Python或Node.js的開發者創建內容?將您的專業知識轉化為額外收入!

鋼鐵支援團隊

我們每週 5 天,每天 24 小時在線上。
聊天
電子郵件
打電話給我